I have two threads A and B. If A completes first, then I have to execute function1 else if B completes first, I need to execute function 2. HOw do I know which of the two threa开发者_如何学运维ds has completed execution first?
You can use the following which will only be set if the previous value was null. (This could be used even if you only have one thread to ensure a value is not changed once set)
AtomicReference<ValueType> ref = new AtomicReference<ValueType>();
ref.compareAndSet(null, value);
One of (many) possible solutions. Have some shared flag variable
import java.util.concurrent.atomic.AtomicInteger;
final AtomicInteger winner = new AtomicInteger(0);
Then at the end of thread's run() method call in first thread
winner.compareAndSet(0, 1);
in second thread
winner.compareAndSet(0, 2);
This way atomic integer will allow to set non zero value only in thread that calls compareAndSet first.
Then you may obtain execution result as winner index with
winner.get()
In production code I would suggest using some constants for initial value and thread indexes.
import java.util.concurrent.Semaphore;
public class ThreadTest {
private Semaphore semaphore = new Semaphore(0);
private String winner;
private synchronized void finished(String threadName) {
if (winner == null) {
winner = threadName;
}
semaphore.release();
}
public void run() {
Runnable r1 = new Runnable() {
public void run() {
try {
Thread.sleep((long) (5000 * Math.random()));
}
catch (InterruptedException e) {
// ignore
}
finally {
finished("thread 1");
}
}
};
Runnable r2 = new Runnable() {
public void run() {
try {
Thread.sleep((long) (5000 * Math.random()));
}
catch (InterruptedException e) {
// ignore
}
finally {
finished("thread 2");
}
}
};
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
try {
semaphore.acquire();
System.out.println("The winner is " + winner);
}
catch (InterruptedException e) {
System.out.println("No winner");
Thread.currentThread().interrupt();
}
}
public static void main(String[] args) {
new ThreadTest().run();
}
}
This solution has the advantage of having a winner as soon as the first thread finishes, instead of having to wait until all the threads are done.
EDIT :
Aa indicated by jtahlborn, CountDownLatch
is a better abstraction for this problem. The same algorithm can thus be written as this :
import java.util.concurrent.CountDownLatch;
public class ThreadTest {
private CountDownLatch latch = new CountDownLatch(1);
private String winner;
private synchronized void finished(String threadName) {
if (winner == null) {
winner = threadName;
}
latch.countDown();
}
public void run() {
Runnable r1 = new Runnable() {
public void run() {
try {
Thread.sleep((long) (5000 * Math.random()));
}
catch (InterruptedException e) {
// ignore
}
finally {
finished("thread 1");
}
}
};
Runnable r2 = new Runnable() {
public void run() {
try {
Thread.sleep((long) (5000 * Math.random()));
}
catch (InterruptedException e) {
// ignore
}
finally {
finished("thread 2");
}
}
};
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
try {
latch.await();
System.out.println("The winner is " + winner);
}
catch (InterruptedException e) {
System.out.println("No winner");
Thread.currentThread().interrupt();
}
}
public static void main(String[] args) {
new ThreadTest().run();
}
}
If you want to wait for the two threads to finish before displaying the winner, you just have to initialize the latch to 2 instead of 1.
精彩评论