我有一个多线程程序,我想让一个线程在所有线程完成后打印语句。我怎么能这样做?我如何知道所有线程都已完成?
ExecutorService pool = Executors.newCachedThreadPool();
for(int i = 0; i < myList.size(); ++i) {
pool.execute (new ThreadProcessRunnable (args));
}
public class ThreadProcessRunnable implements Runnable {
public void run() {
System.out.println("last thread should execute this");
}
}
答案 0 :(得分:3)
这听起来像是ExecutorService.invokeAll
的理想用例:
ExecutorService pool = Executors.newCachedThreadPool();
List<Callable<Object>> tasks = new ArrayList<Callable<Object>>();
for(int i = 0; i < myList.size(); ++i) {
tasks.add (Executors.callable(new ThreadProcessRunnable (args)));
}
List<Future<Object>> futures = pool.invokeAll(tasks);
System.out.println("All tasks finished");
public class ThreadProcessRunnable implements Runnable {
public void run() {
// do some stuff
}
}
invokeAll
阻止,直到提供的List
中的所有任务都完成。
如果你绝对必须在其中一个主题中设置println
&#39; run
方法,那么我能想到的最简单的方法就是在AtomicInteger
中保留某种计数器
public class ThreadProcessRunnable implements Runnable {
private AtomicInteger taskCounter;
public ThreadProcessRunnable(AtomicInteger counter) {
this.taskCounter = counter;
}
public void run() {
// do stuff
if(taskCounter.decrementAndGet() == 0) {
System.out.println("I am the last thread and I am about to finish");
}
}
}
// Main class
ExecutorService pool = Executors.newCachedThreadPool();
AtomicInteger taskCounter = new AtomicInteger(myList.size());
for(int i = 0; i < myList.size(); ++i) {
pool.execute(new ThreadProcessRunnable(taskCounter));
}
使这项工作的关键是taskCounter.decrementAndGet
是 atomic - 例如,taskCounter
的值最初是2,并且两个不同的线程调用{{ 1}}同时保证一个线程将看到值1而另一个线程将看到值0,所以正好一个线程将打印&#34;即将完成&#34;信息。这与MadProgrammer's answer不同,后者涉及竞争条件:
decrementAndGet
其中可以让线程1递减值(为1),然后线程2再次递减它(为0),然后两个线程在它们调用{{1}时看到值0和两者打印消息。
答案 1 :(得分:2)
您可以使用具有屏障操作的CyclicBarrier(documentation)。
创建一个新的CyclicBarrier,当给定的数量时,它会跳闸 派对(线程)正在等待它,它将执行 当屏障被绊倒时,给予屏障作用 最后一个线进入障碍。
答案 2 :(得分:2)
这是使用CountDownLatch
public class TestCountDownLatch {
private static CountDownLatch latch;
public static void main(String[] args) {
latch = new CountDownLatch(10);
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; ++i) {
pool.execute(new Worker(i));
}
}
public static class Worker implements Runnable {
private int number;
public Worker(int number) {
this.number = number;
}
@Override
public void run() {
try {
System.out.println(number + " is sleeping...");
Thread.sleep((long) (Math.round(Math.random() * 1000)));
} catch (InterruptedException ex) {
}
System.out.println(number + " is Completed...");
latch.countDown();
if (latch.getCount() == 0) {
System.out.println(number + " was last...");
}
}
}
}
简单的单线程测试用例
public class TestCountDownLatch {
private static CountDownLatch latch;
public static void main(String[] args) {
latch = new CountDownLatch(1);
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < 1; ++i) {
pool.execute(new Worker(i));
}
}
public static class Worker implements Runnable {
private int number;
public Worker(int number) {
this.number = number;
}
@Override
public void run() {
try {
System.out.println(number + " is sleeping...");
Thread.sleep((long) (Math.round(Math.random() * 1000)));
} catch (InterruptedException ex) {
}
System.out.println(number + " is Completed...");
latch.countDown();
if (latch.getCount() == 0) {
System.out.println(number + " was last...");
}
}
}
}
答案 3 :(得分:1)
您可以将其放在主线程中。调用pool.await()
来阻塞主线程,直到池中的所有线程都完成,然后执行额外的工作。代码如下所示:
ExecutorService pool = Executors.newCachedThreadPool();
for(int i = 0; i < myList.size(); ++i) {
pool.execute (new ThreadProcessRunnable (args));
}
pool.shutdown();
pool.awaitTermination();//blocks the main thread
System.out.println("last thread should execute this");