多线程001 - 主线程等待子线程结束
在很多时候,我们期望实现这么一种功能:在主线程中启动一些子线程,等待所有子线程执行结束后,主线程再继续执行。比如:老板分配任务,众多工人开始工作,等所有工人完成工作后,老板进行检查。
解决方法分析:
- 主线程通过join等待所有子线程完成后,继续执行;
- 主线程知道子线程的数量、未完成子线程数量,主线程等待所有子线程完成后,才继续执行。
通过join实现
第一种方式,可以直接调用Java API中关于线程的join方法等待该线程终止,可以直接实现。
每个工人都是一个线程,其run方法是工作的实现,每个工人通过名字进行区分,具体代码如下:
-
package howe.demo.thread.join;
-
-
-
import java.util.Random;
-
import java.util.concurrent.TimeUnit;
-
-
-
/**
-
* @author liuxinghao
-
* @version 1.0 Created on 2014年9月12日
-
*/
-
public class Worker extends Thread {
-
private String workerName;
-
-
-
public Worker(String workerName) {
-
this.workerName = workerName;
-
}
-
-
-
/**
-
* @see java.lang.Thread#run()
-
*/
-
@Override
-
public void run() {
-
System.out.println(this.workerName + "正在干活...");
-
try {
-
TimeUnit.SECONDS.sleep(new Random().nextInt(10));
-
} catch (InterruptedException e) {
-
}
-
System.out.println(this.workerName + "活干完了!");
-
}
-
-
-
public String getWorkerName() {
-
return workerName;
-
}
-
}
老板招收工人,然后安排工人工作,之后等待工人工作完,检查工人的工作成果(资本家啊。。。),具体代码如下:
-
package howe.demo.thread.join;
-
-
-
import java.util.List;
-
-
-
/**
-
* @author liuxinghao
-
* @version 1.0 Created on 2014年9月12日
-
*/
-
public class Boss {
-
private List<Worker> workers;
-
-
-
public Boss(List<Worker> workers) {
-
System.out.println("老板招收工人。");
-
this.workers = workers;
-
}
-
-
-
public void work() {
-
System.out.println("老板开始安排工人工作...");
-
for (Worker worker : workers) {
-
System.out.println("老板安排" + worker.getWorkerName() + "的工作");
-
worker.start();
-
}
-
System.out.println("老板安排工作结束...");
-
-
-
System.out.println("老板正在等所有的工人干完活......");
-
for (Worker w : workers) {
-
try {
-
w.join();
-
} catch (InterruptedException e) {
-
}
-
}
-
System.out.println("工人活都干完了,老板开始检查了!");
-
}
-
}
现在写main方法进行测试:
-
package howe.demo.thread.join;
-
-
-
import java.util.ArrayList;
-
import java.util.List;
-
-
-
/**
-
* @author liuxinghao
-
* @version 1.0 Created on 2014年9月12日
-
*/
-
public class JoinDemo {
-
public static void main(String[] args) {
-
Worker w1 = new Worker("张三");
-
Worker w2 = new Worker("李四");
-
Worker w3 = new Worker("王五");
-
-
-
List<Worker> workers = new ArrayList<Worker>();
-
workers.add(w1);
-
workers.add(w2);
-
workers.add(w3);
-
-
-
Boss boss = new Boss(workers);
-
boss.work();
-
-
-
System.out.println("main方法结束");
-
}
-
}
执行结果为:
老板招收工人。
老板开始安排工人工作...
老板安排张三的工作
老板安排李四的工作
张三正在干活...
老板安排王五的工作
李四正在干活...
老板安排工作结束...
老板正在等所有的工人干完活......
王五正在干活...
王五活干完了!
张三活干完了!
李四活干完了!
工人活都干完了,老板开始检查了!
main方法结束
通过计数器实现
第二种方式可以自己实现一种计数器,用于统计子线程总数、未完成线程数,当未完成线程数大约0,主线程等待;当未完成线程数等于0,主线程继续执行。
当然,既然我们现在想到这种方式,Java API的团队当然也会想到,JDK 1.5提供了CountDownLatch用于实现上述方法。
于是对上述的工人方法进行修改:
-
package howe.demo.thread.cdl;
-
-
-
import java.util.Random;
-
import java.util.concurrent.CountDownLatch;
-
import java.util.concurrent.TimeUnit;
-
-
-
/**
-
* @author liuxinghao
-
* @version 1.0 Created on 2014-9-12
-
*/
-
public class Worker extends Thread {
-
private CountDownLatch downLatch;
-
private String workerName;
-
-
-
public Worker(CountDownLatch downLatch, String workerName) {
-
this.downLatch = downLatch;
-
this.workerName = workerName;
-
}
-
-
-
public void run() {
-
System.out.println(this.workerName + "正在干活...");
-
try {
-
TimeUnit.SECONDS.sleep(new Random().nextInt(10));
-
} catch (InterruptedException ie) {
-
}
-
System.out.println(this.workerName + "活干完了!");
-
this.downLatch.countDown();
-
}
-
-
-
public String getWorkerName() {
-
return workerName;
-
}
-
}
latch.countDown(),是用于在子线程执行结束后计数器减一,即未完成子线程数减一。
老板类也得做出相应的修改:
-
package howe.demo.thread.cdl;
-
-
-
import java.util.List;
-
import java.util.concurrent.CountDownLatch;
-
-
-
/**
-
* @author liuxinghao
-
* @version 1.0 Created on 2014-9-12
-
*/
-
public class Boss {
-
private List<Worker> workers;
-
private CountDownLatch downLatch;
-
-
-
public Boss(List<Worker> workers, CountDownLatch downLatch) {
-
this.workers = workers;
-
this.downLatch = downLatch;
-
}
-
-
-
public void work() {
-
System.out.println("老板开始安排工人工作...");
-
for (Worker worker : workers) {
-
System.out.println("老板安排" + worker.getWorkerName() + "的工作");
-
worker.start();
-
}
-
System.out.println("老板安排工作结束...");
-
-
-
System.out.println("老板正在等所有的工人干完活......");
-
try {
-
this.downLatch.await();
-
} catch (InterruptedException e) {
-
}
-
System.out.println("工人活都干完了,老板开始检查了!");
-
}
-
-
-
}
latch.await(),是等待子线程结束。
编写main方法进行验证:
-
package howe.demo.thread.cdl;
-
-
-
import java.util.ArrayList;
-
import java.util.List;
-
import java.util.concurrent.CountDownLatch;
-
-
-
/**
-
* @author liuxinghao
-
* @version 1.0 Created on 2014年9月15日
-
*/
-
public class CountDownLatchDemo {
-
public static void main(String[] args) {
-
CountDownLatch latch = new CountDownLatch(3);
-
-
-
Worker w1 = new Worker(latch, "张三");
-
Worker w2 = new Worker(latch, "李四");
-
Worker w3 = new Worker(latch, "王五");
-
-
-
List<Worker> workers = new ArrayList<Worker>();
-
workers.add(w1);
-
workers.add(w2);
-
workers.add(w3);
-
-
-
Boss boss = new Boss(workers, latch);
-
-
-
boss.work();
-
-
-
System.out.println("main方法结束");
-
}
-
}
执行结果为:
老板开始安排工人工作...
老板安排张三的工作
老板安排李四的工作
张三正在干活...
老板安排王五的工作
李四正在干活...
老板安排工作结束...
老板正在等所有的工人干完活......
王五正在干活...
王五活干完了!
李四活干完了!
张三活干完了!
工人活都干完了,老板开始检查了!
main方法结束
使用循环栅栏CyclicBarrier实现
还有一种实现,这种方式不会阻塞主线程,但是会监听所有子线程结束。此处在上述的工人老板的场景中使用的话,代码如下:
工人类:
-
package howe.demo.thread.cyclicbarrier;
-
-
-
import java.util.Random;
-
import java.util.concurrent.BrokenBarrierException;
-
import java.util.concurrent.CyclicBarrier;
-
import java.util.concurrent.TimeUnit;
-
-
-
/**
-
* @author liuxinghao
-
* @version 1.0 Created on 2014年9月12日
-
*/
-
public class Worker extends Thread {
-
private String workerName;
-
private CyclicBarrier barrier;
-
-
-
public Worker(String workerName, CyclicBarrier barrier) {
-
this.workerName = workerName;
-
this.barrier = barrier;
-
}
-
-
-
@Override
-
public void run() {
-
System.out.println(this.workerName + "正在干活...");
-
try {
-
TimeUnit.SECONDS.sleep(new Random().nextInt(10));
-
} catch (InterruptedException e) {
-
}
-
System.out.println(this.workerName + "活干完了!");
-
-
-
try {
-
barrier.await();
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
} catch (BrokenBarrierException e) {
-
e.printStackTrace();
-
}
-
}
-
-
-
public String getWorkerName() {
-
return workerName;
-
}
-
}
老板类:
-
package howe.demo.thread.cyclicbarrier;
-
-
-
import java.util.List;
-
-
-
/**
-
* @author liuxinghao
-
* @version 1.0 Created on 2014-9-12
-
*/
-
public class Boss {
-
private List<Worker> workers;
-
-
-
public Boss(List<Worker> workers) {
-
this.workers = workers;
-
}
-
-
-
public void work() {
-
System.out.println("老板开始安排工人工作...");
-
for (Worker worker : workers) {
-
System.out.println("老板安排" + worker.getWorkerName() + "的工作");
-
worker.start();
-
}
-
System.out.println("老板安排工作结束...");
-
-
-
System.out.println("老板正在等所有的工人干完活......");
-
}
-
-
-
}
main方法测试:
-
package howe.demo.thread.cyclicbarrier;
-
-
-
import java.util.ArrayList;
-
import java.util.List;
-
import java.util.concurrent.CyclicBarrier;
-
-
-
/**
-
* @author liuxinghao
-
* @version 1.0 Created on 2014年9月15日
-
*/
-
public class CyclicBarrierDemo {
-
public static void main(String[] args) {
-
CyclicBarrier barrier = new CyclicBarrier(3, new Runnable() {
-
@Override
-
public void run() {
-
System.out.println("工人活都干完了,老板开始检查了!");
-
}
-
});
-
-
-
Worker w1 = new Worker("张三", barrier);
-
Worker w2 = new Worker("李四", barrier);
-
Worker w3 = new Worker("王五", barrier);
-
-
-
List<Worker> workers = new ArrayList<Worker>();
-
workers.add(w1);
-
workers.add(w2);
-
workers.add(w3);
-
-
-
Boss boss = new Boss(workers);
-
boss.work();
-
-
-
System.out.println("main方法结束");
-
}
-
}
执行结果为:
老板开始安排工人工作...
老板安排张三的工作
老板安排李四的工作
张三正在干活...
老板安排王五的工作
李四正在干活...
老板安排工作结束...
老板正在等所有的工人干完活......
王五正在干活...
main方法结束
李四活干完了!
王五活干完了!
张三活干完了!
工人活都干完了,老板开始检查了!
通过结果分析可以很清楚的看出,boss对象的work方法执行结束后,main方法即开始执行。(此处“老板正在等所有的工人干完活......”打印之后是“王五正在干活...”,然后才是“main方法结束”,是因为对于cpu的抢占,甚至有一定的概率是“main方法结束”会在最后打印。)
假设有这么一个功能,我们需要向数据库批量写入一些记录,然后记录这个操作使用的时间,但是我们又不想影响其他操作(即不想阻塞主线程),这个时候CyclicBarrier就派上用场了。
文章来源: kanshan.blog.csdn.net,作者:看山,版权归原作者所有,如需转载,请联系作者。
原文链接:kanshan.blog.csdn.net/article/details/39299263
- 点赞
- 收藏
- 关注作者
评论(0)