線程基礎----如何編寫java線程池(二)

1、場景:

            在瞭解了線程狀態的轉換,以及java提供的線程調度的一些方法以後,我嘗試寫一個線程池。html

2、線程池的優缺點

            (1)java

談到高併發必然離不開線程池,由於他有以下的優勢:數組

               1.一、下降資源的消耗。經過利用已建立的線程,來下降建立和銷燬帶了的消耗安全

               1.二、當任務到達時候,不須要建立線程就能夠當即執行。併發

               1.三、提升線程的可管理性。線程是稀缺資源,若是無限制的建立,不只會消耗系統資源,還會下降系統的穩定性,使用線程池能夠進行統一的分配,調優和監控。可是要作到合理的利用線程池,必須對其原理了如指掌。ide

           (2)線程池的缺點這裏就不贅述了,能夠 baidugoogle高併發

3、如何編寫線程池

先貼出代碼測試

  線程池主要代碼google

import java.util.LinkedList;
import java.util.List;
 
public class NewThreadPool {
    volatile    int counter =0;
    private static int WORKNUM = 5;
    List<Runnable> taskQueue = new LinkedList<Runnable>();
 
    // 已處理的任務
    private static volatile int finished_task = 0;
    private WorkThread[] workThreads;
    private static NewThreadPool newThreadPool;
 
    private NewThreadPool(int workNum) {
        NewThreadPool.WORKNUM = workNum;
        // 定義一個工做線程數組
        workThreads = new WorkThread[workNum];
        for (int i = 0; i < workThreads.length; i++) {
            workThreads[i] = new WorkThread();
            workThreads[i].start();
        }
    }
 
    // 單例模式得到默認線程個數的線程池
    public static NewThreadPool getThreadPool() {
        return getNewThreadPool(NewThreadPool.WORKNUM);
    }
 
    // 得到傳入參數個數的線程池,大小不能小於默認個數
    public static NewThreadPool getNewThreadPool(int work_num) {
        if (work_num <= 0) {
            work_num = NewThreadPool.WORKNUM;
        }
        if (null == newThreadPool) {
            newThreadPool = new NewThreadPool(work_num);
        }
        return newThreadPool;
    }
 
    //執行線程
    public void execute(Runnable task){
        synchronized (taskQueue) {
            taskQueue.add(task);
            taskQueue.notify();
        }
    }
     
    //批量執行線程任務
    public void execute(Runnable[] task){
        synchronized (taskQueue) {
            for(Runnable t : task ){
                taskQueue.add(t);
                taskQueue.notify();
            }
        }
    }
    public void execute(List<Runnable>task){
        synchronized (taskQueue) {
            for(Runnable t : task){
                taskQueue.add(t);
                taskQueue.notify();
            }
        }
    }
    //返回工做線程的個數
    public int getWorkedThreadNumbers(){
        return WORKNUM;
    }
    //返回已經完成的線程任務
    public int getFinishedTaskNumbers(){
        return finished_task;
    }
     
    //返回尚未完成任務的的線程個數
    public int getWaitTaskNumbers(){
        return taskQueue.size();
    }
     
    //銷燬線程池方法,等到全部線程都完成以後纔會銷燬
    public void destory(){
        while(!taskQueue.isEmpty()){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        for(int i=0;i<WORKNUM;i++){
            workThreads[i].stopWorker();
            workThreads[i] = null;
        }
        newThreadPool = null;
        taskQueue.clear();
    }
    // 覆蓋toString方法,返回線程池信息:工做線程個數和已完成任務個數
        @Override
        public String toString() {
            return "WorkThread number:" + WORKNUM + "  finished task number:"
                    + finished_task + "  wait task number:" + getWaitTaskNumbers();
        }
     
    // 工做線程
    private class WorkThread extends Thread {
        private boolean isRunning = true;
        @Override
        public void run() {
             
            Runnable r = null;
            while (isRunning) {
                synchronized (taskQueue) {
                    while (isRunning && taskQueue.isEmpty()) {
                        try {
                            taskQueue.wait(20);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    // 因爲是隊列,取第0個
                    if (!taskQueue.isEmpty()) {
                        r = taskQueue.remove(0);
                    }
                }
                if (null != r) {
                    r.run();
                    //stopWorker();
                }
                System.out.println(Thread.currentThread().getName() + "------------" + counter++  +"-----" + getWaitTaskNumbers());
                finished_task++;
                r = null;
            }
        }
        // 中止工做,讓該線程天然執行完run方法,天然結束
        public void stopWorker() {
            isRunning = false;
        }
    }
}

以及測試demo.net

//測試線程池
public class TestThreadPool {
    public static void main(String[] args) {
        // 建立3個線程的線程池
        NewThreadPool t = NewThreadPool.getNewThreadPool(10);
        t.execute(new Runnable[] { new Task(), new Task(), new Task() , new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task()});
        t.execute(new Runnable[] { new Task(), new Task(), new Task() , new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task()});
        System.out.println(t);
        //t.destory();// 全部線程都執行完成才destory
        System.out.println(t);
        t.execute(new Runnable[] { new Task(), new Task(), new Task() , new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task()});
     
    }
 
    // 任務類
    static class Task implements Runnable {
        private static volatile int i = 1;
 
        @Override
        public void run() {// 執行任務
            System.out.println("任務 " + (i++) + " 完成");
        }
    }
}

以上爲線程池代碼。參看了不少網友的博客,而後才理解了這個線程池的代碼,而後按着理解寫出了這個。若是發現有和網友代碼有相似,不要驚奇,我是初學者請見諒。呵呵

(三)總結:

         在編寫線程池的時候,咱們須要有一個基本的思路。須要一個基本的思路,一個安全的線程隊列用來存放線程。按照要求初始化默認數量的線程,而且啓動它,讓這些線程在等待隊列中等待,而後當目標任務來時,將其喚醒得到鎖而後處理目標任務。

         因爲隊列是不安全的,因此在線程添加到隊列,和從隊列中取出來的時候,都須要同步synchroniza,保證其安全。還有一個概念就是一旦線程池中run方法跑完,那麼它的生命週期也就結束了。線程狀態轉換,參考 線程基礎(詳細介紹線程狀態轉換) ,因此再咱們須要一個信號量,將工做線程的run方法中加上信號量,這樣就能夠保證,線程池中線程能夠重用,只有當你銷燬線程池的時候,全部線程纔會銷燬。

相關文章
相關標籤/搜索