java 線程池

10.1 爲什麼使用線程池(Why Thread Pools?)

線程池在java多線程開發中用的非常普遍,它裏面存放了一定數量的Thread,當有任務需要執行的時候,(通常是Runnable對象),就從線程池裏面拿出空閒的Thread來執行任務,執行完了之後再把Thread放回去等待下一個任務。


使用線程池的理由如下


1)創建一個Thread的開銷是很大的,使用線程池可以省去這部分的開銷,對有些對時間敏感的工程來說,是必須的

2)第二個原因是方便我們的程序設計,如果你有太多的線程需要你去維護,這是一個很繁瑣的工程,使用線程池可以你管理,讓你把精力投入到具體的邏輯當中

3)第三個原因是線程池可以讓多個線程併發運行


這裏需要說明一下併發和並行的區別,併發就好比一個人同時吃三個饅頭,並行相當於三個人吃三個饅頭,專業一點就是,併發是一個CPU運行多個任務,並行是多個CPU運行多個任務


爲了方便理解,我模擬了一個線程池


package com.yellow;
import java.util.LinkedList;
/**
 * 線程池的模擬
 *
 * @author yellowbaby
 *
 */
public class ThreadPool extends ThreadGroup {
    /**
     * 用來存放Task的工作隊列
     */
    private LinkedList<Runnable> workQueue = new LinkedList<Runnable>();
    public ThreadPool(int poolSize) {
        super("");// 父類無參數的構造函數是private的
        startWorkThreads(poolSize);
    }
    /**
     * 開啓工作線程
     * @param poolSize
     */
    private void startWorkThreads(int poolSize) {
        for (int i = 0; i < poolSize; i++) {
            new WorkThread(i).start();
        }
    }
    /**
     * 執行任務
     * @param task
     */
    public synchronized void execute(Runnable task) {
        if (task != null) {
            workQueue.add(task);//往工作隊列裏面添加一個任務
            notify();//喚醒一個正在等待的工作線程
        }
    }
    /**
     * 工作線程從工作隊列裏面取task,如果工作隊列爲空,就等待
     */
    private synchronized Runnable getTask() {
        while (workQueue.size() == 0) {
            try {
                System.out.println("工作線程 " + Thread.currentThread().getName()
                        + " 正在等待任務");
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return workQueue.removeFirst();
    }
    /**
     * 工作線程,從隊列裏面取Task,取到了就執行,沒有就等待
     */
    private class WorkThread extends Thread {
        public WorkThread(int id) {
            super(ThreadPool.this, id + "");// 將當前線程加入當前ThreadGroup,並且把線程重命名
        }
        @Override
        public void run() {
            while (!interrupted()) {
                Runnable task = getTask();
                if (task == null)
                    return;
                task.run();
            }
        }
    }
    /**
     * 測試類
     * @param args
     */
    public static void main(String[] args) {
        ThreadPool threadPool = new ThreadPool(3);
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 10; i++) {
            threadPool.execute(createTask(i));
        }
    }
    public static Runnable createTask(final int id) {
        return new Runnable() {
            @Override
            public void run() {
                System.out.println("工作線程 " + Thread.currentThread().getName()
                        + " 正在執行Task" + id);
            }
        };
    }
}



這是執行結果


工作線程 0 正在等待任務
工作線程 1 正在等待任務
工作線程 2 正在等待任務
工作線程 0 正在執行Task0
工作線程 1 正在執行Task2
工作線程 2 正在執行Task1
工作線程 2 正在執行Task5
工作線程 2 正在執行Task6
工作線程 2 正在執行Task7
工作線程 2 正在執行Task8
工作線程 2 正在執行Task9
工作線程 2 正在等待任務
工作線程 1 正在執行Task4
工作線程 1 正在等待任務
工作線程 0 正在執行Task3
工作線程 0 正在等待任務


可以看出,線程池在初始化的時候就啓動了3個線程,然後一直處於等待任務的狀態,任務加入後,3個線程併發執行,當所有的任務都完成後,工作線程又處於等待狀態



現在來看看如果我們使用JDK裏面的線程池應該怎麼寫


package com.yellow;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * 線程池的模擬
 *
 * @author yellowbaby
 *
 */
public class ThreadPool {
    /**
     * 測試類
     * @param args
     */
    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newFixedThreadPool(3);//創建一個固定有三個工作線程的線程池
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 10; i++) {
            threadPool.execute(createTask(i));
        }
    }
    public static Runnable createTask(final int id) {
        return new Runnable() {
            @Override
            public void run() {
                System.out.println("工作線程 " + Thread.currentThread().getName()
                        + " 正在執行Task" + id);
            }
        };
    }
}






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