簡單實現java線程池


使用多線程以及線程池的意義無需多說,要想掌握線程池,最好的方法還是自己手動去實現。

 

一、實現思路

                      (網絡盜圖)

 

二、實現代碼

1、線程池類

package com.ty.thread; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; /** * @author Taoyong * @date 2018年5月17日 * 天下沒有難敲的代碼! */
public class ThreadPoolExecutor { /* * BlockingQueue是阻塞隊列,在兩種情況下出現阻塞: * 1、當隊列滿了,入隊列操作時; * 2、當隊列空了,出隊列操作時。 * 阻塞隊列是線程安全的,主要使用在生產/消費者的場景 */
    private BlockingQueue<Task> blockingQueue; //線程池的工作線程數(可以認為是線程池的容量)
    private int poolSize = 0; //線程池的核心容量(也就是當前線程池中真正存在的線程個數)
    private int coreSize = 0; /* * 此地方使用volatile關鍵字,volatile的工作原理是:對於JVM維度來說,每個線程持有變量的工作副本,那對於計算機維度來說, * 就是這些變量的中間值會存放在高速緩存中。通過volatile關鍵字,告知每個線程改變此變量之后,立馬更新到內存中去,並且使得 * 緩存中的數據失效,這樣來保證其中某個線程改變公有變量后,其他線程能及時讀取到最新的變量值,從而保證可見性。 * 原因如下: * 1、在ThreadPoolExecutorTest中操作shutDown,這是main線程操作此變量(由於變量是volatile聲明,所以會立馬寫入內存中); * 2、Worker中線程通過while(!shutDown)來判斷當前線程是否應該關閉,因此需通過volatile保證可見性,使線程可以及時得到關閉。 */
    private volatile boolean shutDown = false; public ThreadPoolExecutor(int size) { this.poolSize = size; //LinkedBlockingQueue的大小可以指定,不指定即為無邊界的。
        blockingQueue = new LinkedBlockingQueue<>(poolSize); } public void execute(Task task) throws InterruptedException { if(shutDown == true) { return; } if(coreSize < poolSize) { /* * BlockingQueue中的插入主要有offer(obj)以及put(obj)兩個方法,其中put(obj)是阻塞方法,如果插入不能馬上進行, * 則操作阻塞;offer(obj)則是插入不能馬上進行,返回true或false。 * 本例中的Task不允許丟失,所以采用put(obj); */ blockingQueue.put(task); produceWorker(task); }else { blockingQueue.put(task); } } private void produceWorker(Task task) throws InterruptedException { if(task == null) { throw new NullPointerException("非法參數:傳入的task對象為空!"); } Thread thread = new Thread(new Worker()); thread.start(); coreSize++; } /* * 真正中斷線程的方法,是使用共享變量發出信號,告訴線程停止運行。 * */
    public void shutDown() { shutDown = true; } /* * 此內部類是實際上的工作線程 * */
    class Worker implements Runnable { @Override public void run() { while(!shutDown) { try { //  blockingQueue.take().doJob(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("線程:" + Thread.currentThread().getName() + "退出運行!"); } } }

 

2、Task類(需要被線程處理的任務類)

package com.ty.thread; /** * @author Taoyong * @date 2018年5月17日 * 天下沒有難敲的代碼! */
public class Task { //通過taskId對任務進行標識
    private int taskId; public Task(int taskId) { this.taskId = taskId; } public void doJob() { System.out.println("線程" + Thread.currentThread().getName() + "正在處理任務!"); } public int getId() { return taskId; } }

 

 3、測試類

package com.ty.thread; /** * @author Taoyong * @date 2018年5月17日 * 天下沒有難敲的代碼! */
public class ThreadPoolExecutorTest { public static void main(String[] args) throws InterruptedException { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3); for(int i = 0; i < 10; i++) { Task task = new Task(i); threadPoolExecutor.execute(task); } threadPoolExecutor.shutDown(); } }

 

4、運行結果

線程Thread-0正在處理任務! 線程Thread-1正在處理任務! 線程Thread-0正在處理任務! 線程Thread-1正在處理任務! 線程Thread-2正在處理任務! 線程Thread-0正在處理任務! 線程Thread-1正在處理任務! 線程:Thread-1退出運行! 線程:Thread-0退出運行! 線程Thread-2正在處理任務! 線程:Thread-2退出運行!

 

當第十個任務待處理時,整個線程池已經被shutDown,整個流程結束。

項目代碼已經上傳到github中:https://github.com/ali-mayun/threadPool


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM