JAVA 線程池入門事例


  線程池這個概念已經深入人心了,今天就是通過幾個入門事例,學習一下線程池在JAVA中的應用。

一、大小固定的線程池——Executors.newFixedThreadPool()

  下面咱們明確兩個類:

  1、ExecutorService:線程池的接口類

  2、Executors:Java里面線程池的頂級接口是Executor,但是嚴格意義上講Executor並不是一個線程池,而只是一個執行線程的工具

  3、Executors.newFixedThreadPool():這是一個靜態方法,也是這個事例的核心,目的是創建固定大小的線程池。每次提交一個任務就創建一個線程,直到線程達到線程池的最大值。線程池的大小一旦達到最大值就會保持不變,如果某個線程因為執行異常而結束,那么線程池會補充一個新線程。

package com.taobao.threadpool;

import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;

/**
 * 線程池的應用
 * @author liqiu
 *
 */
public class Test {
    public static void main(String[] args) {
        // 創建一個可重用固定線程數的線程池
        ExecutorService pool = Executors.newFixedThreadPool(3);
        // 將線程放入池中進行執行
        for (int i=0; i<9; i++){
            pool.execute(new MyThread(i));
        }
        // 關閉線程池
        pool.shutdown();
    }
}

class MyThread extends Thread {
    int num;
    public MyThread(int i){
        this.num = i;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "正在執行。。。" + this.num);
    }
}

  執行的結果:

pool-1-thread-1正在執行。。。0
pool-1-thread-1正在執行。。。3
pool-1-thread-1正在執行。。。4
pool-1-thread-3正在執行。。。2
pool-1-thread-3正在執行。。。6
pool-1-thread-3正在執行。。。7
pool-1-thread-3正在執行。。。8
pool-1-thread-2正在執行。。。1
pool-1-thread-1正在執行。。。5

二、其他的Executores方法

  1、Executors.newSingleThreadExecutor():創建一個單線程的線程池。這個線程池只有一個線程在工作,也就是相當於單線程串行執行所有任務。如果這個唯一的線程因為異常結束,那么會有一個新的線程來替代它。此線程池保證所有任務的執行順序按照任務的提交順序執行。這種用法我認為違背了線程池的概念,畢竟是一個池子,竟然只有一條魚,很沒勁。事例和上一個一樣,有興趣的話自己試一試。

  2、Executors.newCachedThreadPool():創建一個可緩存的線程池。如果線程池的大小超過了處理任務所需要的線程,那么就會回收部分空閑(60秒不執行任務)的線程,當任務數增加時,此線程池又可以智能的添加新線程來處理任務。此線程池不會對線程池大小做限制,線程池大小完全依賴於操作系統(或者說JVM)能夠創建的最大線程大小。說白了就是默認有若干個線程,如果請求增多了,也會繼續增加線程的個數,但是會自動自動回收超出的部分線程。

  3、Executors.newScheduledThreadPool():創建一個大小無限的線程池。此線程池支持定時以及周期性執行任務的需求。

  4、Executors.newSingleThreadExecutor():創建一個單線程的線程池。此線程池支持定時以及周期性執行任務的需求。

三、自定義線程池

  閱讀了上面的內容,應該已經可以使用JAVA提供的線程池了,但是有一個特殊的情況還是需要咱們特制線程池。

package com.taobao.threadpool;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 線程池的應用
 * 
 * @author liqiu
 * 
 */
public class Test {
    public static void main(String[] args) {
        // 創建等待隊列
        BlockingQueue bqueue = new ArrayBlockingQueue(20);
        // 創建一個單線程執行程序,它可安排在給定延遲后運行命令或者定期地執行。
        ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 3, 2, TimeUnit.MILLISECONDS, bqueue);
        // 創建實現了Runnable接口對象,Thread對象當然也實現了Runnable接口
        for (int i = 0; i <= 9; i++) {
            // 將線程放入池中進行執行
            pool.execute(new MyThread(i));
        } 
        // 關閉線程池
        pool.shutdown();
    }
}

class MyThread extends Thread {
    int num;
    public MyThread(int i){
        this.num = i;
    }
    @Override
    public void run() {
        System.out.println(this.num+" 正在被"+Thread.currentThread().getName() + "執行。。。");
        try {
            Thread.sleep(100L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

執行的結果:

0 正在被pool-1-thread-1執行。。。
1 正在被pool-1-thread-2執行。。。
2 正在被pool-1-thread-1執行。。。
3 正在被pool-1-thread-2執行。。。
4 正在被pool-1-thread-1執行。。。
5 正在被pool-1-thread-2執行。。。
6 正在被pool-1-thread-1執行。。。
7 正在被pool-1-thread-2執行。。。
8 正在被pool-1-thread-1執行。。。
9 正在被pool-1-thread-2執行。。。

下面解釋一下程序:

ThreadPoolExecutor 類的方法:

  public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue)

  參數說明名如下:
  corePoolSize - 池中所保存的線程數,包括空閑線程。

  maximumPoolSize - 池中允許的最大線程數。

  keepAliveTime - 當線程數大於核心時,此為終止前多余的空閑線程等待新任務的最長時間。

  unit - keepAliveTime 參數的時間單位。

  workQueue - 執行前用於保持任務的隊列。此隊列僅保持由 execute 方法提交的 Runnable 任務。本例實用的是BlockingQueue,有關它的內容可以參考:http://www.cnblogs.com/liqiu/p/3630281.html

小結:

  可見用給定的初始參數和默認的線程工廠及處理程序創建新的 ThreadPoolExecutor。使用 Executors 工廠方法之一比使用此通用構造方法方便得多。


免責聲明!

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



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