執行緒池的建立⽅法總共有 7 種,但總體來說可分為 2 類:
- 透過 ThreadPoolExecutor 建立的執行緒池;
- 透過 Executors 建立的執行緒池
前置步驟
public class ThreadTask implements Runnable{
Logger logger = LoggerFactory.getLogger(ThreadDemo.class);
private String taskName;
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
public ThreadTask(String name) {
this.setTaskName(name);
}
@Override
public void run() {
logger.info("執行緒-----------{},執行",taskName);
}
}
public class FixedThreadDemo extends ThreadTask {
Logger logger = LoggerFactory.getLogger(ThreadDemo.class);
private Boolean isAdd ;
private static Integer count = 0;
public FixedThreadDemo(String name,Boolean isAdd ) {
super(name);
this.isAdd = isAdd;
}
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
lock.lock();
for (int i = 0 ; i < 100;i++){
if (isAdd){
count++;
}else {
count--;
}
logger.info("執行緒{}--------執行,執行模式:{},執行結果:{}",this.getTaskName(),isAdd?"加執行緒":"減執行緒",count);
}
lock.unlock();
}
}
Executors 建立執行緒池
newFixedThreadPool()
Executors.newFixedThreadPool:建立⼀個固定⼤⼩的執行緒池,可控制併發的執行緒數,超出的執行緒會在佇列中等待,直到一個執行緒可用。如果任何執行緒在關閉之前的執行過程中由於失敗而終止,如果需要執行後續任務,則會有一個新執行緒取代它的位置。在顯式關閉池之前,池中的執行緒將一直存在。
public class FixedThreadPool {
private ExecutorService executors;
private static Logger logger = LoggerFactory.getLogger(FixedThreadPool.class);
@PostConstruct
public void init(){
// 引數 1、表示池中允許存在的最大執行緒數
// 引數 2、表示一個執行緒,自己建立的,可以不用,主要用來記錄日誌
executors = Executors.newFixedThreadPool(2,r -> {
logger.info("建立執行緒:{} ",r.hashCode());
Thread thread = new Thread(r);
return thread;
});
}
// 自定義方法,用於執行執行緒任務
// 使用submit可以執行有返回值的任務或者是無返回值的任務;而execute只能執行不帶返回值的任務。
public void executor(ThreadTask threadTask){
executors.submit(threadTask);
}
}
測試:
期望值:0 實際結果:0
由於建立執行緒池指定了 最大執行緒數是 2,當我線上程池中去加入執行緒的時候,此時符合2的場景,第三個執行緒會等待前兩個執行緒中其中一個結束後才會執行。
newCachedThreadPool()
Executors.newCachedThreadPool:建立⼀個可快取的執行緒池,若執行緒數超過處理所需,快取⼀段時間後會回收,若執行緒數不夠,則新建執行緒;
public class CachedThreadPool {
private static Logger logger = LoggerFactory.getLogger(CachedThreadPool.class);
private ExecutorService executorService;
public void init(){
executorService = Executors.newCachedThreadPool(t->{
logger.info("可快取的執行緒池{}",t.hashCode());
return new Thread(t);
});
}
// 自定義方法,用於執行執行緒任務
// 使用submit可以執行有返回值的任務或者是無返回值的任務;而execute只能執行不帶返回值的任務。
public void executor(ThreadTask threadTask){
executorService.submit(threadTask);
}
}
執行結果 0
newSingleThreadExecutor()
Executors.newSingleThreadExecutor:建立單個執行緒數的執行緒池,它可以保證先進先出的執⾏順序;
/**
* @author zhangguangfeng
* @date 2024/8/15
* 建立單個執行緒數的執行緒池,它可以保證先進先出的執⾏順序;
*/
public class SingleThreadPool {
private static Logger logger = LoggerFactory.getLogger(SingleThreadPool.class);
private ExecutorService executorService;
public void init(){
executorService = Executors.newSingleThreadExecutor(t->{
logger.info("可執⾏順序的執行緒池{}",t.hashCode());
return new Thread(t);
});
}
// 自定義方法,用於執行執行緒任務
// 使用submit可以執行有返回值的任務或者是無返回值的任務;而execute只能執行不帶返回值的任務。
public void executor(ThreadTask threadTask){
executorService.submit(threadTask);
}
}
public static void main(String[] args) {
ThreadTask task1 = new FixedThreadDemo("執行緒1",Boolean.TRUE);
ThreadTask task2 = new FixedThreadDemo("執行緒2",Boolean.FALSE);
// 執行順序的執行緒池
SingleThreadPool singleThreadPool = new SingleThreadPool();
singleThreadPool.init();
singleThreadPool.executor(task1);
singleThreadPool.executor(task2);
}
在這裡可以看到,在程式碼順序上,先執行task1,後執行task2,檢視執行結果是否如此,按照指定順序執行。
可以看到,是按照順序執行的,假設去設定優先順序,是否會打亂這個順序呢?
並不會打亂這個順序,原因:如它的設定一樣,只存在單個執行緒在執行,本質上就是單執行緒的。
newScheduledThreadPool()
Executors.newScheduledThreadPool:建立⼀個可以執⾏延遲任務的執行緒池;
public class SingleThreadPool {
private static Logger logger = LoggerFactory.getLogger(SingleThreadPool.class);
private ScheduledExecutorService scheduledExecutorService;
public void init(){
scheduledExecutorService = Executors.newScheduledThreadPool(2,t->{
logger.info("可延遲任務的執行緒池{}",t.hashCode());
return new Thread(t);
});
}
// 自定義方法,用於執行執行緒任務
public void executor(ThreadTask threadTask){
// 提交一個定時任務,在 5 秒後執行
scheduledExecutorService.schedule(threadTask,5, TimeUnit.SECONDS);
}
// 自定義方法,用於執行週期性任務
public void executorAtFixedRate(ThreadTask threadTask){
// 提交一個週期性任務,每5秒執行一次,初始延遲1秒
scheduledExecutorService.scheduleAtFixedRate(threadTask,1,5, TimeUnit.SECONDS);
}
}
執行結果:
可以看到,相隔五秒後才執行。
執行緒測試 週期任務,初始延遲1s,每個5s週期執行
Executors.newSingleThreadScheduledExecutor
建立⼀個單執行緒的可以執⾏延遲任務的執行緒池;
Executors.newWorkStealingPool
建立⼀個搶佔式執⾏的執行緒池(任務執⾏順序不確定)【JDK1.8 新增】
ThreadPoolExecutor
ThreadPoolExecutor:最原始的建立執行緒池的⽅式,它包含了 7 個引數可供設定,
ThreadPoolExecutor 引數說明
詳細連結:https://blog.csdn.net/m0_48273471/article/details/124171220