实际开发过程中,尤其是大型的业务系统中或批量处理系统中,我们通常会用到多线程来进行任务拆分,来提高系统的处理能力。当对业务不断拆分时,多线程各自任务之间也形成了错综复杂的关系。
我们常常遇到这样的情况,业务模块A 拆分成了 A1 、A2.....An个多线程,来提高处理速度,可是 Ak(1
我们先定义两个实现多线程任务:
任务1:
public classWorkA1 extendsThread {
@Overridepublic voidrun() {
System.out.println("WorkA1 开始执行");try{
Thread.sleep(2000);} catch(InterruptedException e) {
e.printStackTrace();}
System.out.println("WorkA1 结束执行");}
}
任务2:
public classWorkA2 extendsThread {
@Overridepublic voidrun() {
System.out.println("WorkA2 开始执行");try{
Thread.sleep(1800);} catch(InterruptedException e) {
e.printStackTrace();}
System.out.println("WorkA2 结束执行");}
}
主线程开始实现是这样的:
public classThreedClient {
public static voidmain(String[] args) {
System.out.println("准备开始执行任务");WorkA1 workA1 = newWorkA1();WorkA2 workA2 = newWorkA2();workA1.start();workA2.start();System.out.println("执行完成了。");}
}
执行结果是:
准备开始执行任务
执行完成了。
WorkA1 开始执行
WorkA2 开始执行
WorkA2 结束执行
WorkA1 结束执行
如果我们想最后打印 “执行完成了”在所有子线程完成后,怎么办呢?
我们对主线程进行改造:
改造方法1:
public classThreedClient {
public static voidmain(String[] args) {
System.out.println("准备开始执行任务");WorkA1 workA1 = newWorkA1();WorkA2 workA2 = newWorkA2();workA1.start();workA2.start();try{
workA1.join();workA2.join();}catch(InterruptedException e){
e.printStackTrace();}
System.out.println("执行完成了。");}
}
改造完成后,在看执行结果:
准备开始执行任务
WorkA2 开始执行
WorkA1 开始执行
WorkA2 结束执行
WorkA1 结束执行
执行完成了。
OK,达到我们的预期了。
改造方法2:
CountDownLatch允许一个或多个线程等待其他线程完成操作。CountDownLatch的构造函数接收一个int类型的参数作为计数器,如果你想等待N个点完成,这里就传入N。当我们调用countDown方法时,N就会减1,await方法会阻塞当前线程,直到N变成0。
它的原理很简单,就是你需要等待几个任务时,就先定义好,然后任务执行完成一个,计数器减1。看看具体实现:
public classWorkA1 extendsThread {
privateCountDownLatch countDownLatch;publicWorkA1(CountDownLatch countDownLatch) {
this.countDownLatch= countDownLatch;}
@Overridepublic voidrun() {
System.out.println("WorkA1 开始执行");try{
Thread.sleep(2000);} catch(InterruptedException e) {
e.printStackTrace();}finally{
countDownLatch.countDown();}
System.out.println("WorkA1 结束执行");}
}
Work2的改造跟Work1完全一样,就不再单独贴代码了。
看下主线程中的改造:
public classThreedClient {
public static voidmain(String[] args) {
System.out.println("准备开始执行任务");CountDownLatch countDownLatch = newCountDownLatch(2);WorkA1 workA1 = newWorkA1(countDownLatch);WorkA2 workA2 = newWorkA2(countDownLatch);workA1.start();workA2.start();try{
countDownLatch.await();}catch(InterruptedException e){
e.printStackTrace();}
System.out.println("执行完成了。");}
}
我们看下改造后的执行结果:
准备开始执行任务
WorkA1 开始执行
WorkA2 开始执行
WorkA2 结束执行
WorkA1 结束执行
执行完成了。
跟改造1中的效果一模一样。