您好,登錄后才能下訂單哦!
這篇文章主要介紹了java如何編寫屬于自己的線程池,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
什么是線程池
線程池就是以一個或多個線程[循環執行]多個應用邏輯的線程集合.
一般而言,線程池有以下幾個部分:
完成主要任務的一個或多個線程.
用于調度管理的管理線程.
要求執行的任務隊列.
線程池的作用:
線程池作用就是限制系統中執行線程的數量。
根據系統的環境情況,可以自動或手動設置線程數量,達到運行的最佳效果;少了浪費了系統資源,多了造成系統擁擠效率不高。用線程池控制線程數量,其他線程排隊等候。一個任務執行完畢,再從隊列的中取最前面的任務開始執行。若隊列中沒有等待進程,線程池的這一資源處于等待。當一個新任務需要運行時,如果線程池中有等待的工作線程,就可以開始運行了;否則進入等待隊列。
自己實現線程池
根據如上對線程池的理解,我們自己編寫一個屬于自己的簡單線程池:
簡單的線程池接口:
public interface ThreadPool<Job extends Runnable>{ //執行一個任務(Job),這個Job必須實現Runnable void execute(Job job); //關閉線程池 void shutdown(); //增加工作者線程,即用來執行任務的線程 void addWorkers(int num); //減少工作者線程 void removeWorker(int num); //獲取正在等待執行的任務數量 void getJobSize(); }
客戶端可以通過execute(Job)方法將Job提交入線程池來執行,客戶端完全不用等待Job的執行完成。除了execute(Job)方法以外,線程池接口提供了增加/減少工作者線程以及關閉線程池的方法。每個客戶端提交的Job都會進入到一個工作隊列中等待工作者線程的處理。
線程池接口的默認實現
public class DefaultThreadPool<Job extends Runnable> implements ThreadPool<Job>{ // 線程池維護工作者線程的最大數量 private static final int MAX_WORKER_NUMBERS = 10; // 線程池維護工作者線程的默認值 private static final int DEFAULT_WORKER_NUMBERS = 5; // 線程池維護工作者線程的最小數量 private static final int MIN_WORKER_NUMBERS = 1; // 維護一個工作列表,里面加入客戶端發起的工作 private final LinkedList<Job> jobs = new LinkedList<Job>(); // 工作者線程的列表 private final List<Worker> workers = Collections.synchronizedList(new ArrayList<Worker>()); // 工作者線程的數量 private int workerNum; // 每個工作者線程編號生成 private AtomicLong threadNum = new AtomicLong(); //生成線程池 public DefaultThreadPool() { this.workerNum = DEFAULT_WORKER_NUMBERS; initializeWorkers(this.workerNum); } public DefaultThreadPool(int num) { if (num > MAX_WORKER_NUMBERS) { this.workerNum =DEFAULT_WORKER_NUMBERS; } else { this.workerNum = num; } initializeWorkers(this.workerNum); } //初始化每個工作者線程 private void initializeWorkers(int num) { for (int i = 0; i < num; i++) { Worker worker = new Worker(); //添加到工作者線程的列表 workers.add(worker); //啟動工作者線程 Thread thread = new Thread(worker); thread.start(); } } public void execute(Job job) { if (job != null) { //根據線程的"等待/通知機制"這里必須對jobs加鎖 synchronized (jobs) { jobs.addLast(job); jobs.notify(); } } } //關閉線程池即關閉每個工作者線程 public void shutdown() { for (Worker w : workers) { w.shutdown(); } } //增加工作者線程 public void addWorkers(int num) { //加鎖,防止該線程還么增加完成而下個線程繼續增加導致工作者線程超過最大值 synchronized (jobs) { if (num + this.workerNum > MAX_WORKER_NUMBERS) { num = MAX_WORKER_NUMBERS - this.workerNum; } initializeWorkers(num); this.workerNum += num; } } //減少工作者線程 public void removeWorker(int num) { synchronized (jobs) { if(num>=this.workerNum){ throw new IllegalArgumentException("超過了已有的線程數量"); } for (int i = 0; i < num; i++) { Worker worker = workers.get(i); if (worker != null) { //關閉該線程并從列表中移除 worker.shutdown(); workers.remove(i); } } this.workerNum -= num; } } public int getJobSize() { // TODO Auto-generated method stub return workers.size(); } //定義工作者線程 class Worker implements Runnable { // 表示是否運行該worker private volatile boolean running = true; public void run() { while (running) { Job job = null; //線程的等待/通知機制 synchronized (jobs) { if (jobs.isEmpty()) { try { jobs.wait();//線程等待喚醒 } catch (InterruptedException e) { //感知到外部對該線程的中斷操作,返回 Thread.currentThread().interrupt(); return; } } // 取出一個job job = jobs.removeFirst(); } //執行job if (job != null) { job.run(); } } } // 終止該線程 public void shutdown() { running = false; } } }
從線程池的實現中可以看出,當客戶端調用execute(Job)方法時,會不斷地向任務列表jobs中添加Job,而每個工作者線程會不讀的從jobs上獲取Job來執行,當jobs為空時,工作者線程進入WAITING狀態。
當添加一個Job后,對工作隊列jobs調用其notify()方法來喚醒一個工作者線程。此處我們不調用notifyAll(),避免將等待隊列中的線程全部移動到阻塞隊列中而造成資源浪費。
線程池的本質就是使用了一個線程安全的工作隊列連接工作者線程和客戶端線程。客戶端線程把任務放入工作隊列后便返回,而工作者線程則不端的從工作隊列中取出工作并執行。當工作隊列為空時,工作者線程進入WAITING狀態,當有客戶端發送任務過來后會通過任意一個工作者線程,隨著大量任務的提交,更多的工作者線程被喚醒。
感謝你能夠認真閱讀完這篇文章,希望小編分享的“java如何編寫屬于自己的線程池”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。