![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/a3afa1556f282b002b98f46a1735a1af.gif)
Java基础 -- 多线程的使用,执行完所有子线程,再继续执行主线程
1. 场景描述
- 在开发过程中,对一些大数据量的操作,往往会使用多线程,但是我们想在这些任务执行完成后,才接着再执行的话,就需要使用下面这些手段,不然主线程结束了,子线程也就结束了。
重点:
在实际生产过程中,因为每条线程都有逻辑要处理,所以线程的数量并不能随便设定,还要参考电脑虚拟内存的大小,比如我的电脑已经开启了很多应用,现在本地测试还想开20条线程,可是通过log发现,我的程序在目前状态只能开启最多10条线程。
2. CountDownLatch
2.1 Introduction
- 这个类使一个线程等待其他线程各自执行完毕后再执行。是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,countdownLatch.countDown()计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,在CountDownLatch上await()的线程就会被唤醒,然后继续执行下面的工作。
2.2 Code
public class CountDownLatchThead extends Thread {
private int num;
private CountDownLatch countDownLatch;
public CountDownLatchThead(int num,CountDownLatch countDownLatch) {
this.num = num;
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
super.run();
System.out.println("the thread num is :"+num);
try {
Thread.sleep(10 * 1000);
System.out.println("我睡了10s,the thread num is :"+num);
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2.3 Test
public void demo04() throws InterruptedException{
CountDownLatch countDownLatch = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
Thread thread = new CountDownLatchThead(i,countDownLatch);
thread.start();
}
countDownLatch.await();
System.out.println("子线程执行完,主线程继续执行");
}
3. CyclicBarrier
- 我服了,这个鬼东西一直没达到我想要的效果 2023-2-28
3.1 Introduction
- CyclicBarrier 的源码实现和 CountDownLatch 大同小异,CountDownLatch 基于 AQS 的共享模式的使用,而 CyclicBarrier 基于 Condition 来实现的。在CyclicBarrier类的内部有一个计数器,允许一组线程到达某个栅栏点(common barrier point)互相等待,直到最后一个线程到达栅栏点,栅栏才会打开,处于阻塞状态的线程恢复继续执行。每个线程在到达屏障点的时候都会调用await方法将自己阻塞,此时计数器会减1,当计数器减为0的时候所有因调用await方法而被阻塞的线程将被唤醒。这就是实现一组线程相互等待的原理。
3.2 Code
public class CyclicBarrierThead extends Thread {
private int num;
private CyclicBarrier cyclicBarrier;
public CyclicBarrierThead(int num,CyclicBarrier cyclicBarrier) {
this.num = num;
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
super.run();
System.out.println("the thread num is :"+num);
try {
Thread.sleep(10 * 1000);
System.out.println("CyclicBarrier,我睡了10s,the thread num is :"+num);
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}
3.3 Test
public void demo06() throws Exception{
CyclicBarrier cyclicBarrier = new CyclicBarrier(10);
for (int i = 0; i < 10; i++) {
Thread thread = new CyclicBarrierThead(i,cyclicBarrier);
thread.start();
}
//cyclicBarrier.await();
System.out.println("子线程执行完,主线程继续执行");
}
3.4 CountDownLatch和CyclicBarrier的比较
- 1.CountDownLatch是线程组之间的等待,即一个(或多个)线程等待N个线程完成某件事情之后再执行;而CyclicBarrier则是线程组内的等待,即每个线程相互等待,即N个线程都被拦截之后,然后依次执行。
- 2.CountDownLatch是减计数方式,而CyclicBarrier是加计数方式。
- 3.CountDownLatch计数为0无法重置,而CyclicBarrier计数达到初始值,则可以重置。
- 4.CountDownLatch不可以复用,而CyclicBarrier可以复用。
4. ThreadPool
public static void main(String[] args) throws Exception {
int N = 10;// 线程个数
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(N);
for (int i = 0; i < N; i++) {
fixedThreadPool.submit(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("子线程结束");
}
}
});
}
//停止接收外部submit的任务
fixedThreadPool.shutdown();
// 等待子线程结束,再继续执行下面的代码
fixedThreadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);//阻塞,等待所有子线程执行完成
System.out.println("结束");
}
5. Awakening
在一秒钟内看到本质的人和花半辈子也看不清一件事本质的人,自然是不一样的命运。