執行緒池建立的幾種方式

自学Java笔记本發表於2024-08-15

執行緒池的建立⽅法總共有 7 種,但總體來說可分為 2 類:

  1. 透過 ThreadPoolExecutor 建立的執行緒池;
  2. 透過 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);
    }

}

測試:
image

期望值: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,檢視執行結果是否如此,按照指定順序執行。
image
可以看到,是按照順序執行的,假設去設定優先順序,是否會打亂這個順序呢?
並不會打亂這個順序,原因:如它的設定一樣,只存在單個執行緒在執行,本質上就是單執行緒的。

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);
    }
}

執行結果:
image
可以看到,相隔五秒後才執行。
執行緒測試 週期任務,初始延遲1s,每個5s週期執行
image

Executors.newSingleThreadScheduledExecutor

建立⼀個單執行緒的可以執⾏延遲任務的執行緒池;

Executors.newWorkStealingPool

建立⼀個搶佔式執⾏的執行緒池(任務執⾏順序不確定)【JDK1.8 新增】

ThreadPoolExecutor

ThreadPoolExecutor:最原始的建立執行緒池的⽅式,它包含了 7 個引數可供設定,
ThreadPoolExecutor 引數說明
image

詳細連結:https://blog.csdn.net/m0_48273471/article/details/124171220

相關文章