java線程池實現(附源碼)

java線程池實現

線程池是一種多線程處理形式,處理過程中將任務添加到隊列,然後在創建線程後自動啓動這些任務。

五種Java線程池功能及分析

線程池都繼承了ExecutorService的接口

因爲繼承了ExecutorService接口,ExecutorService是Java提供的用於管理線程池的類。
該類的兩個作用:控制線程數量和重用線程。
只有調用了shutdown()的時候纔是正式的終止了這個線程池。

四種常見的線程池詳解

java通過Executors工廠類提供我們的線程池一共有4種:

Executors.newFixedThreadPool(int n) //啓動固定線程數的線程池

Executors.newCacheThreadPool() //按需分配的線程池

Executors.newScheduledThreadPool(int n)//定時,定期執行任務的線程池

Executors.newSingleThreadExecutor()://單線程化的線程池。

一、單線程化的線程池newSingleThreadExecutor

串行執行所有任務

 /**
     * 單線程化的線程池
     * 串行執行所有任務
     */
    public void singleThreadPool() throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            Future<Integer> task = executorService.submit(() -> {
                Thread.currentThread().setName("Thread i = " + index);
                System.out.println("執行單線程化的線程池:" + Thread.currentThread().getName());
                return 50;
            });
            System.out.println("第" + i + "次計算,結果:" + task.get());
        }

        //銷燬線程池
        executorService.shutdown();
    }

二、固定線程數的線程池newFixedThreadPool

fixedThreadPool(int size) 就只有一個參數,size,就是線程池中最大可創建多少個線程。
如下:創建2個線程的fixedThreadPool ,當2個都爲活躍的時候,後面的任務會被加入無邊界的鏈式隊列,有空閒,就執行任務。

/**
     * 啓動固定線程數的線程池
     *
     * @param size 線程池中最大可創建多少個線程
     * @throws ExecutionException   執行異常
     * @throws InterruptedException 中斷異常
     */
    public void fixedThreadPool(int size) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(size);
        for (int i = 0; i < 10; i++) {
            Future<Integer> task = executorService.submit(() -> {
                System.out.println("執行線程" + Thread.currentThread().getName());
                return 40;
            });
            System.out.println("第" + i + "次計算,結果:" + task.get());
        }

        //銷燬線程池
        executorService.shutdown();
    }

三、按需分配的線程池newCacheThreadPool

CachedThreadPool比fixedThreadPool更快,只要有任務並且其他線程都在活躍態,就會開啓一個新的線程。最大線程數:Integer.MAX_VALUE = 0x7fffffff

/**
     * 按需分配的線程池
     * CachedThreadPool比fixedThreadPool更快
     * 只要有任務並且其他線程都在活躍態,就會開啓一個新的線程
     * 最大線程數:Integer.MAX_VALUE = 0x7fffffff
     */
    public void cacheThreadPool() throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            Future<Integer> task = executorService.submit(() -> {
                System.out.println("執行線程" + Thread.currentThread().getName());
                return 50;
            });
            System.out.println("第" + i + "次計算,結果:" + task.get());
        }

        //銷燬線程池
        executorService.shutdown();
    }

四、定時執行的線程池newScheduledThreadPool

newScheduledThreadPool有schedule和scheduleAtFixedRate方法用來做定時任務,scheduleAtFixedRate多了一個週期的參數period

schedule(Runnable command,long delay, TimeUnit unit)
scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)

代碼如下:

/**
     * 定時定期的線程池
     */
    public void scheduledThreadPool() {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);

        //延遲3s後運行
        for (int i = 0; i < 10; i++) {
            scheduledThreadPool.schedule(() ->
                    System.out.println("執行線程" + Thread.currentThread().getName()), 10, TimeUnit.SECONDS);
        }

//        scheduledThreadPool.scheduleAtFixedRate(() ->
//                System.out.println("scheduleAtFixedRate:執行線程" + Thread.currentThread().getName()), 1,1, TimeUnit.SECONDS);

        //銷燬線程池
        scheduledThreadPool.shutdown();
    }

自定義線程池newFixedThreadPool

ThreadPoolExecutor()//指定線程數的線程池。

ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) 

自定義線程池,可以用ThreadPoolExecutor類創建,它有多個構造方法來創建線程池。

corePoolSize 核心線程池大小
maximumPoolSize 最大線程池大小----30
keepAliveTime 線程池中超過corePoolSize數目的空閒線程最大存活時間
TimeUnit keepAliveTime時間單位----TimeUnit.MINUTES
workQueue 阻塞隊列
threadFactory 新建線程工廠
rejectedExecutionHandler 當提交任務數超過maxmumPoolSize+workQueue之和時, 任務會交給RejectedExecutionHandler來處理。

提交任務

可以向ThreadPoolExecutor提交兩種任務:Callable和Runnable。

  1. Callable

    該類任務有返回結果,可以拋出異常。
    通過submit函數提交,返回Future對象。
    可通過get獲取執行結果。

  2. Runnable

    該類任務只執行,無法獲取返回結果,並在執行過程中無法拋異常。
    通過execute提交。

關閉線程池

關閉線程池有兩種方式:shutdown和shutdownNow,關閉時,會遍歷所有的線程,調用它們的interrupt函數中斷線程。但這兩種方式對於正在執行的線程處理方式不同。

  1. shutdown()

    僅停止阻塞隊列中等待的線程,那些正在執行的線程就會讓他們執行結束。

  2. shutdownNow()

    不僅會停止阻塞隊列中的線程,而且會停止正在執行的線程。

最大線程數一般設爲2N+1最好,N是CPU核數

public static void main(String[] args) {
        CustomThreadPoolExecutor exec = new CustomThreadPoolExecutor();

        //1. 初始化
        exec.init();

        ExecutorService executorService = exec.getCustomThreadPoolExecutor();

        for (int i = 0; i < 100; i++) {
            System.out.println("提交第" + i + "個任務");
            executorService.execute(() -> {
                try {
                    System.out.println("執行自定義的線程池:" + Thread.currentThread().getName());
                    TimeUnit.SECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        try {
            //銷燬
            Thread.sleep(1000);
            exec.destory();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

源碼

碼雲路徑:https://gitee.com/lhblearn/ThreadPool

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章