多線程 自己開發一個線程池

每一個線程的啓動和結束都是比較消耗時間和佔用資源的。
如果在系統中用到了很多的線程,大量的啓動和結束動作會導致系統的性能變卡,響應變慢。
爲了解決這個問題,引入線程池這種設計思想。
線程池的模式很像生產者消費者模式,消費的對象是一個一個的能夠運行的任務

線程池的思路

線程池的思路和生產者消費者模型是很接近的。

  1. 準備一個任務容器
  2. 一次性啓動10個 消費者線程
  3. 剛開始任務容器是空的,所以線程都wait在上面。
  4. 直到一個外部線程往這個任務容器中扔了一個“任務”,就會有一個消費者線程被喚醒notify
  5. 這個消費者線程取出“任務”,並且執行這個任務,執行完畢後,繼續等待下一次任務的到來。
  6. 如果短時間內,有較多的任務加入,那麼就會有多個線程被喚醒,去執行這些任務。

在整個過程中,都不需要創建新的線程,而是循環使用這些已經存在的線程
在這裏插入圖片描述

開發一個自定義線程池

package multiplethread;
import java.util.LinkedList;
public class ThreadPool {
    // 線程池大小
    int threadPoolSize;
    // 任務容器
    LinkedList<Runnable> tasks = new LinkedList<Runnable>();
    // 試圖消費任務的線程
    public ThreadPool() {
        threadPoolSize = 10;
        // 啓動10個任務消費者線程
        synchronized (tasks) {
            for (int i = 0; i < threadPoolSize; i++) {
                new TaskConsumeThread("任務消費者線程 " + i).start();
            }
        }
    }
  
    public void add(Runnable r) {
        synchronized (tasks) {
            tasks.add(r);
            // 喚醒等待的任務消費者線程
            tasks.notifyAll();
        }
    }
  
    class TaskConsumeThread extends Thread {
        public TaskConsumeThread(String name) {
            super(name);
        }
        Runnable task;
        public void run() {
            System.out.println("啓動: " + this.getName());
            while (true) {
                synchronized (tasks) {
                    while (tasks.isEmpty()) {
                        try {
                            tasks.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    task = tasks.removeLast();
                    // 允許添加任務的線程可以繼續添加任務
                    tasks.notifyAll();
                }
                System.out.println(this.getName() + " 獲取到任務,並執行");
                task.run();
            }
        }
    }
}

測試線程池

創造一個情景,每個任務執行的時間都是1秒
剛開始是間隔1秒鐘向線程池中添加任務
然後間隔時間越來越短,執行任務的線程還沒有來得及結束,新的任務又來了。就會觀察到線程池裏的其他線程被喚醒來執行這些任務。

package multiplethread;
public class TestThread {
    public static void main(String[] args) {
        ThreadPool pool= new ThreadPool();
        int sleep=1000;
        while(true){
            pool.add(new Runnable(){
                @Override
                public void run() {
                    //System.out.println("執行任務");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            });
            try {
                Thread.sleep(sleep);
                sleep = sleep>100?sleep-100:sleep;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在這裏插入圖片描述

使用java自帶線程池

java提供自帶的線程池,而不需要自己去開發一個自定義線程池了。
線程池類ThreadPoolExecutor在包java.util.concurrent下

ThreadPoolExecutor threadPool= new ThreadPoolExecutor(10, 15, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

第一個參數10 表示這個線程池初始化了10個線程在裏面工作
第二個參數15 表示如果10個線程不夠用了,就會自動增加到最多15個線程
第三個參數60 結合第四個參數TimeUnit.SECONDS,表示經過60秒,多出來的線程還沒有接到活兒,就會回收,最後保持池子裏就10個
第四個參數TimeUnit.SECONDS 如上
第五個參數 new LinkedBlockingQueue() 用來放任務的集合

execute方法用於添加新的任務

package multiplethread;
   
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
   
public class TestThread {
   
    public static void main(String[] args) throws InterruptedException {
           
        ThreadPoolExecutor threadPool= new ThreadPoolExecutor(10, 15, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
        //execute方法用於添加新的任務
        threadPool.execute(new Runnable(){
            @Override
            public void run() {
                // TODO Auto-generated method stub
                System.out.println("任務1");
            }
               
        });
   
    }
   
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章