您的位置:首页 > 其它

多线程执行时,如果一个逻辑需要等若干个线程执行完成后再执行,怎么实现?

2018-12-14 11:05 10 查看

实际开发过程中,尤其是大型的业务系统中或批量处理系统中,我们通常会用到多线程来进行任务拆分,来提高系统的处理能力。当对业务不断拆分时,多线程各自任务之间也形成了错综复杂的关系。

我们常常遇到这样的情况,业务模块A 拆分成了 A1 、A2.....An个多线程,来提高处理速度,可是 Ak(1<k<n)这个线程执行时,它有依赖关系,它必须等 Ak-1 和Ak-2这两个进程执行完,才能执行,以免造成业务混乱,那怎么实现?

我们先定义两个实现多线程任务:

任务1:

public class WorkA1 extends Thread {
@Override
public void run() {
System.out.println("WorkA1 开始执行");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("WorkA1 结束执行");
}
}

任务2:

public class WorkA2 extends Thread {
@Override
public void run() {
System.out.println("WorkA2 开始执行");
try {
Thread.sleep(1800);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("WorkA2 结束执行");
}
}

主线程开始实现是这样的:

public class ThreedClient {
public static void main(String[] args) {
System.out.println("准备开始执行任务");
WorkA1 workA1 = new WorkA1();
WorkA2 workA2 = new WorkA2();
workA1.start();
workA2.start();
System.out.println("执行完成了。");
}
}

执行结果是:

准备开始执行任务
执行完成了。
WorkA1 开始执行
WorkA2 开始执行
WorkA2 结束执行
WorkA1 结束执行

如果我们想最后打印 “执行完成了”在所有子线程完成后,怎么办呢?

我们对主线程进行改造:

改造方法1:

public class ThreedClient {
public static void main(String[] args) {
System.out.println("准备开始执行任务");
WorkA1 workA1 = new WorkA1();
WorkA2 workA2 = new WorkA2();
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 class WorkA1 extends Thread {
private CountDownLatch countDownLatch;
public WorkA1(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
System.out.println("WorkA1 开始执行");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
countDownLatch.countDown();
}
System.out.println("WorkA1 结束执行");
}
}

Work2的改造跟Work1完全一样,就不再单独贴代码了。

看下主线程中的改造:

public class ThreedClient {
public static void main(String[] args) {
System.out.println("准备开始执行任务");
CountDownLatch countDownLatch = new CountDownLatch(2);
WorkA1 workA1 = new WorkA1(countDownLatch);
WorkA2 workA2 = new WorkA2(countDownLatch);
workA1.start();
workA2.start();
try {
countDownLatch.await();
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("执行完成了。");
}
}

 我们看下改造后的执行结果:

准备开始执行任务
WorkA1 开始执行
WorkA2 开始执行
WorkA2 结束执行
WorkA1 结束执行
执行完成了。

跟改造1中的效果一模一样。

(adsbygoogle = window.adsbygoogle || []).push({});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Count_Down
相关文章推荐