1. 程式人生 > >使用線程池優化Echo模型

使用線程池優化Echo模型

exceptio reads linked ava final 系統內存 extend 參數 first

  在上一篇文章中 http://www.cnblogs.com/gosaint/p/8492356.html 我闡述了使用線程為每一個客戶端創建一個工作線程來負責任務的執行。但是會存在如下的問題

  1.   服務器創建線程開銷很大,有可能服務器創建線程消耗資源要比單獨的和客戶端通信所消耗的資源要大
  2.   如果存在大量的線程要同時創建,那麽存在的內存開銷很大。可能導致服務器系統內存不夠
  3. 線程之間的切換消耗了大量的資源

  創建線程池可以較少線程的創建和銷毀的開銷,並且根據實際情況動態的調整線程池的大小。

  (1) 自定以線程池,讓它繼承ThreadGroup類

技術分享圖片

如下代碼是自定義線程池代碼的實現

package com.asiaInfo.caozg.ch_03.threadPool;

import java.util.LinkedList;

/**
 * @Authgor: gosaint
 * @Description:
 * @Date Created in 15:39 2018/3/2
 * @Modified By:自定義線程池的實現
 */
public class ThreadPool extends ThreadGroup {

    private boolean isClosed = false;//線程池是否關閉
    private LinkedList<Runnable> workQuee;//
表示工作隊列 private static int threadPoolID;//表示線程池ID private int workThreadID;//表示工作線程池ID public ThreadPool(int poolSize) { //poolSize表示線程池中工作線程的數目 //每一次的初始化,線程池ID都會自動增加 super("ThreadPool-" + (threadPoolID++)); //設置為守護線程 setDaemon(true); workQuee = new LinkedList<>();//
創建工作隊列 for (int i = 0; i < poolSize; i++) { new WorkThread().start(); } } /** * 向工作隊列中添加一個新的任務,讓工作線程去執行 * * @param task */ public synchronized void execute(Runnable task) { if (isClosed) { //線程池關閉,則拋出如下的異常 throw new IllegalStateException(); } if (task != null) { workQuee.add(task); notify();//喚醒正在等待獲取任務的工作線程getTask(); } } /** * 從工作隊列中取出一個線程,讓線程執行任務 * * @return * @throws InterruptedException */ public synchronized Runnable getTask() throws InterruptedException { while (workQuee.size() == 0) { //當工作隊列中的線程為0時,如果線程池關閉,則返回null.負責,等待任務 if (isClosed) { return null; } else { wait(); } } return workQuee.removeFirst();//從工作隊列中彈出第一個元素 } /** * 關閉線程池 */ public synchronized void closed() { //線程池沒有關閉 if (!isClosed) { isClosed = true; workQuee.clear();//清除工作隊列 interrupt();//中斷所有的線程 } } /** * 等在工作線程將若有的任務執行完畢 */ public void join() { synchronized (this) { isClosed = true; notifyAll();//喚醒所有的等待任務的工作線程 } //activeCount() 返回此線程組中活動線程的估計數。 來自ThreadGroup Thread[] threads = new Thread[activeCount()]; // enumerate[list] 把此線程組及其子組中的所有活動線程復制到指定數組中。 int count = enumerate(threads);//返回所有的活著的線程數量 for (int i = 0; i < count; i++) { try { threads[i].join();//等待所有的活動的工作宣稱的結束 } catch (InterruptedException e) { e.printStackTrace(); } } } /** * 內部類,創建的工作線程對象 */ private class WorkThread extends Thread { public WorkThread() { super(ThreadPool.this, "WorkThread-" + workThreadID++); } @Override public void run() { //線程沒有中斷 while (!isInterrupted()) { Runnable task = null; try { task = getTask();//獲取任務 } catch (InterruptedException e) { e.printStackTrace(); } if (task == null) { return; } try { task.run();//運行任務 } catch (Throwable t) { t.printStackTrace(); } } } } }

1 流程執行的分析:

技術分享圖片

關註兩個成員變量:

  1> isClosed---->表示線程池是否關閉;workQuee:表示的工作隊列,使用的類型是LinkedList.

  2> 在構造器中初始化工作隊列,然後啟動每一個線程;

  3>execute()方法的執行如下所示:線程池對象的核心就是將線程添加到工作隊列中

  4>getTask()方法 從工作隊列中獲取線程

  5> closed()方法:關閉線程池

  6>join()方法;等待線程執行完所有的任務

技術分享圖片

2 測試自定義線程池:

package com.asiaInfo.caozg.ch_03.threadPool;

import static java.lang.Integer.parseInt;

/**
 * @Authgor: gosaint
 * @Description:
 * @Date Created in 16:25 2018/3/2
 * @Modified By:線程池測試
 */
public class ThreadPoolTester {

    public static void main(String[] args) {
        if (args.length != 2) {
            System.out.println(
                    "用法: java ThreadPoolTest numTasks poolSize");
            System.out.println(
                    "  numTasks - integer: 任務的數目");
            System.out.println(
                    "  numThreads - integer: 線程池中的線程數目");
            return;
        }
        int numTasks = Integer.parseInt(args[0]);
        int poolSize = Integer.parseInt(args[1]);

        ThreadPool threadPool = new ThreadPool(poolSize);  //創建線程池

        // 運行任務
        for (int i = 0; i < numTasks; i++)
            threadPool.execute(createTask(i));

        threadPool.join();  //等待工作線程完成所有的任務
        // threadPool.close(); //關閉線程池
    }//#main()

    /**
     * 定義了一個簡單的任務(打印ID)
     */
    private static Runnable createTask(final int taskID) {
        return new Runnable() {
            public void run() {
                System.out.println("Task " + taskID + ": start");
                try {
                    Thread.sleep(500);  //增加執行一個任務的時間
                } catch (InterruptedException ex) {
                }
                System.out.println("Task " + taskID + ": end");
            }
        };
    }
}

設置參數5,3.表示5個任務3個線程去執行:

技術分享圖片

使用線程池優化Echo模型