java线程池并行
一:CountDownLatch
1.1:概念
CountDownLatch是在jdk1.5的时候被引入的,位于java.util.concurrent并发包中,CountDownLatch叫做闭锁,也叫门闩。
CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程执行完后再执行。
举个例子,班长和五个同学都在教室里面写作业,班长必须等待五个同学都走了之后,才能把教室门锁上,CountDownLatch就提供了类似这种一个线程需要等待其他线程都执行完成之后,自己再去执行
1.2:原理
CountDownLatch是通过一个计数器来实现的,计数器的初始化值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就相应的减1。当计数器的值减到0时,表示所有的线程都已完成任务,然后在CountDownLatch上等待的线程就可以恢复执行接下来的任务
1.3:常用方法
1.4:使用示例一:主线程等待所有的子线程执行完成后,再执行
import org.junit.Test;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadTesst01 {
@Test
public void test01() throws InterruptedException {
// 创建线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(8, 16, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1024));
int taskCount = 100;
CountDownLatch countDownLatch = new CountDownLatch(taskCount);
for (int i = 0; i < taskCount; i++) {
threadPoolExecutor.submit(() -> {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ">>执行结束!");
// 当前线程调用此方法,则计数减一
countDownLatch.countDown();
});
}
// 判断是不是所有任务执行结束
// 阻塞当前线程(此例子就是main主线程),直到计数器的值为0,主线程才开始处理
countDownLatch.await();
System.out.println("执行完成");
}
}
1.5:使用场景
有时我们想同时启动多个线程,实现最大程度的并行性。如果我们创建一个初始计数器为1的CountDownLatch,多个线程在开始执行任务前首先countdownlatch.awaitO)在这个锁上等待,只需要主线程调用一次countDown(方法就可以让其他所有等待的线程同时恢复执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。
开始执行前等待N个线程完成各自任务后,进行汇总合并:例如,我们需要使用多线程统计完所有的数据之后,做一个汇总,就可以使用CountDownLatch
1.6:缺点
CountDownLatch是一次性的,计数器的值只能在构造方法中初始化一次,之后不能再次对其设置值,当CountDownLatch使用完毕后,它不能再次被使用。
二:Semaphore
java.util.concurrent.Semaphore
参考:https://www.bilibili.com/video/BV1ta41117f9/?spm_id_from=333.337.search-card.all.click&vd_source=aa4e16557c3a6622877c08d8d7a0a57f
2.1:概念
Semaphore是一个计数信号量,是JDK1.5引入的一个并发工具类,位于java.util.concurrent包中。Semaphore翻译成字面意思为“信号量”,可以控制同时访问资源的线程个数。
举个例子,公园里面的厕所只有5个坑,假如有10个人要上厕所的话,那么同时能去上厕所的人就只能有5个,还剩下5个人只能在外面等待。当5个人中有任何一个人离开后,其中在等待的五个人中又有一个人可以使用了,依次下去,直到所有人都上完厕所。
2.2:原理
Semphore计数信号量由一个指定数量的“许可"初始化。每调用一次 acquire(),一个许可会被调用线程取走。每调用一次release(),一个许可会被返还给信号量。因此,在没有任何release()调用时,最多有N个线程能够通过acquire()方法,N是该信号量初始化时的许可的指定数量。这些许可只是一个简单的计数器。
可以简单理解为:信号量中有很多n个令牌,每个线程执行任务时,需要先获取到一块令牌才能执行,那么最多就只允许n个线程同时执行任务,其他线程阻塞在那里等待获取令牌。当其他线程执行完任务后,会把令牌还回去,这时候其他线程就可以获取令牌了。
2.3:常用方法
2.4:测试代码
import org.junit.Test; import java.util.concurrent.*; public class ThreadTesst01 { @Test public void test01() { // 创建线程池 int taskCount = 100; Semaphore semaphore = new Semaphore(5); for (int i = 1; i <= taskCount; i++) { new SemaphoreThread(semaphore, i).start(); } System.out.println("执行完成"); } private class SemaphoreThread extends Thread { private Semaphore semaphore; private int index; public SemaphoreThread (Semaphore semaphore, int index) { this.semaphore = semaphore; this.index = index; } @Override public void run() { try { // 获取许可 semaphore.acquire(); System.out.println("第"+ index + "个任务开始执行!"); Thread.sleep(10000); System.out.println("第"+ index + "个任务结束执行!"); } catch (InterruptedException e) { e.printStackTrace(); } finally { // 释放许可 semaphore.release(); } } } }
2.5;使用场景
信号量Semaphore可以用来做限流,控制同时访问资源的线程数量或者用户数量等
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY