Java多線程和線程池(轉)

1.爲何要使用線程池html

在java中,若是每一個請求到達就建立一個新線程,開銷是至關大的。在實際使用中,服務器在建立和銷燬線程上花費的時間和消耗的系統資源都至關大,甚至可能要比在處理實際的用戶請求的時間和資源要多的多。除了建立和銷燬線程的開銷以外,活動的線程也須要消耗系統資源。若是在一個jvm裏建立太多的線程,可能會使系統因爲過分消耗內存或「切換過分」而致使系統資源不足。爲了防止資源不足,服務器應用程序須要採起一些辦法來限制任何給定時刻處理的請求數目,儘量減小建立和銷燬線程的次數,特別是一些資源耗費比較大的線程的建立和銷燬,儘可能利 
用已有對象來進行服務,這就是「池化資源」技術產生的緣由。
java

線程池主要用來解決線程生命週期開銷問題和資源不足問題。經過對多個任務重複使用線程,線程建立的開銷就被分攤到了多個任務上了,並且因爲在請求到達時線程已經存在,因此消除了線程建立所帶來的延遲。這樣,就能夠當即爲請求服務,使用應用程序響應更快。另外,經過適當的調整線程中的線程數目能夠防止出現資源不足的狀況。web

2.線程池的組成部分spring

一個比較簡單的線程池至少應包含線程池管理器、工做線程、任務列隊、任務接口等部分。其中線程池管理器的做用是建立、銷燬並管理線程池,將工做線程放入線程池中;工做線程是一個能夠循環執行任務的線程,在沒有任務是進行等待;任務列隊的做用是提供一種緩衝機制,將沒有處理的任務放在任務列隊中;任務接口是每一個任務必須實現的接口,主要用來規定任務的入口、任務執行完後的收尾工做、任務的執行狀態等,工做線程經過該接口調度任務的執行。服務器

線程池管理器至少有下列功能:建立線程池,銷燬線程池,添加新任務。jvm

工做線程是一個能夠循環執行任務的線程,在沒有任務時將等待。this

任務接口是爲全部任務提供統一的接口,以便工做線程處理。任務接口主要規定了任務的入口,任務執行完後的收尾工做,任務的執行狀態等。spa

3.線程池適合應用的場合.net

當一個服務器接受到大量短小線程的請求時,使用線程池技術是很是合適的,它能夠大大減小線程的建立和銷燬次數,提升服務器的工做效率。可是線程要求的運動時間比較長,即線程的運行時間比…….線程

以上信息來自以下文章:http://www.blogjava.net/stevenjohn/archive/2011/12/12/366161.html

1、Java自帶線程池

先看看Java自帶線程池的例子,開啓5個線程打印字符串List:

package com.luo.test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadTest {

    public static void main(String[] args) {

        List<String> strList = new ArrayList<String>();
        for (int i = 0; i < 100; i++) {
            strList.add("String" + i);
        }
        int threadNum = strList.size() < 5 ? strList.size() : 5;
        ThreadPoolExecutor executor = new ThreadPoolExecutor(2, threadNum, 300,
                TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(3),
                new ThreadPoolExecutor.CallerRunsPolicy());
        for (int i = 0; i < threadNum; i++) {
            executor.execute(new PrintStringThread(i,strList,threadNum));
        }
        executor.shutdown();
    }
}

class PrintStringThread implements Runnable {

    private int num;

    private List<String> strList;

    private int threadNum;

    public PrintStringThread(int num, List<String> strList, int threadNum) {
        this.num = num;
        this.strList = strList;
        this.threadNum = threadNum;
    }

    public void run() {
        int length = 0;
        for(String str : strList){
            if (length % threadNum == num) {
                System.out.println("線程編號:" + num + ",字符串:" + str);
            }
            length ++;
        }
    }
}
 

Java自帶線程池構造方法

ThreadPoolExecutor(int corePoolSize, 
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue
RejectedExecutionHandler handler)

corePoolSize: 線程池維護線程的最少線程數,也是核心線程數,包括空閒線程
maximumPoolSize: 線程池維護線程的最大線程數
keepAliveTime: 線程池維護線程所容許的空閒時間
unit: 程池維護線程所容許的空閒時間的單位
workQueue: 線程池所使用的緩衝隊列
handler: 線程池對拒絕任務的處理策略

當一個任務經過execute(Runnable)方法欲添加到線程池時:
1、 若是此時線程池中的數量小於corePoolSize,即便線程池中的線程都處於空閒狀態,也要建立新的線程來處理被添加的任務。
2、 若是此時線程池中的數量等於 corePoolSize,可是緩衝隊列 workQueue未滿,那麼任務被放入緩衝隊列。
3、若是此時線程池中的數量大於corePoolSize,緩衝隊列workQueue滿,而且線程池中的數量小於maximumPoolSize,建新的線程來處理被添加的任務。
4、 若是此時線程池中的數量大於corePoolSize,緩衝隊列workQueue滿,而且線程池中的數量等於maximumPoolSize,那麼經過 handler所指定的策略來處理此任務。也就是:處理任務的優先級爲:核心線程corePoolSize、任務隊列workQueue、最大線程 maximumPoolSize,若是三者都滿了,使用handler處理被拒絕的任務。
五、 當線程池中的線程數量大於 corePoolSize時,若是某線程空閒時間超過keepAliveTime,線程將被終止。這樣,線程池能夠動態的調整池中的線程數。
 

事實上上面的例子代碼寫得有不足之處,若是你看出不足之處,說明你理解了線程池。不然能夠多看幾遍哦。

2、Spring線程池配置

3.一、直接調用

ThreadPoolTaskExecutor poolTaskExecutor = new ThreadPoolTaskExecutor();  
//線程池所使用的緩衝隊列  
poolTaskExecutor.setQueueCapacity(200);  
//線程池維護線程的最少數量  
poolTaskExecutor.setCorePoolSize(5);  
//線程池維護線程的最大數量  
poolTaskExecutor.setMaxPoolSize(1000);  
//線程池維護線程所容許的空閒時間  
poolTaskExecutor.setKeepAliveSeconds(30000);  
poolTaskExecutor.initialize(); 

 

3.二、經過配置文件

 
<bean id="poolTaskExecutor"      class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
   <!-- 核心線程數,默認爲1 -->
   <property name="corePoolSize" value="5" />
   <!-- 最大線程數,默認爲Integer.MAX_VALUE -->
   <property name="maxPoolSize" value="50" />
   <!-- 隊列最大長度,通常須要設置值>=notifyScheduledMainExecutor.maxNum;默認爲Integer.MAX_VALUE -->
   <property name="queueCapacity" value="2000" />
   <!-- 線程池維護線程所容許的空閒時間,默認爲60s -->
   <property name="keepAliveSeconds" value="100" />
   <!-- 線程池對拒絕任務(無線程可用)的處理策略,目前只支持AbortPolicy、CallerRunsPolicy;默認爲後者 -->
   <property name="rejectedExecutionHandler">
       <!-- AbortPolicy:直接拋出java.util.concurrent.RejectedExecutionException異常 -->
       <!-- CallerRunsPolicy:主線程直接執行該任務,執行完以後嘗試添加下一個任務到線程池中,能夠有效下降向線程池內添加任務的速度 -->
       <!-- DiscardOldestPolicy:拋棄舊的任務、暫不支持;會致使被丟棄的任務沒法再次被執行 -->
       <!-- DiscardPolicy:拋棄當前任務、暫不支持;會致使被丟棄的任務沒法再次被執行 -->
       <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
   </property>
</bean>
相關文章
相關標籤/搜索