1. 程式人生 > >2、使用SPRING中的執行緒池ThreadPoolTaskExecutor實現JAVA併發

2、使用SPRING中的執行緒池ThreadPoolTaskExecutor實現JAVA併發

new Thread的弊端如下:
a. 每次new Thread新建物件效能差。
b. 執行緒缺乏統一管理,可能無限制新建執行緒,相互之間競爭,及可能佔用過多系統資源導致宕機或oom。
c. 缺乏更多功能,如定時執行、定期執行、執行緒中斷。
相比new Thread,Java提供的四種執行緒池的好處在於:
a. 重用存在的執行緒,減少物件建立、消亡的開銷,效能佳。
b. 可有效控制最大併發執行緒數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞。
c. 提供定時執行、定期執行、單執行緒、併發數控制等功能。

1、java執行緒池

Java通過Executors提供四種執行緒池,分別為:
newCachedThreadPool建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閒執行緒,若無可回收,則新建執行緒。


newFixedThreadPool 建立一個定長執行緒池,可控制執行緒最大併發數,超出的執行緒會在佇列中等待。
newScheduledThreadPool 建立一個定長執行緒池,支援定時及週期性任務執行。
newSingleThreadExecutor 建立一個單執行緒化的執行緒池,它只會用唯一的工作執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行。

package com.java.my;

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

/**
 * @author wanjiadong
 * @description
 * @date Create in 14:01 2018/2/1
 */
public class test2 {
    public static void main(String[] args) throws InterruptedException {
        //建立一個定長執行緒池,可控制執行緒最大併發數,超出的執行緒會在佇列中等待
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        long beginTime = System.currentTimeMillis();
        for(int i =0;i<10;i++){
            System.out.println("建立執行緒:"+i);
            final int index = i;
            Runnable run = new Runnable() {
                @Override
                public void run() {
                    System.out.println("啟動執行緒:"+index);
                }
            };
            // 在未來某個時間執行給定的命令
            executorService.execute(run);
        }
        //關閉啟動執行緒
        executorService.shutdown();
        //等待子執行緒結束,再執行下面程式碼
        executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
        System.out.println("所有執行緒都結束了,用時為:"+(System.currentTimeMillis()-beginTime));
    }
}

2、使用SPRING中的執行緒池ThreadPoolTaskExecutor實現JAVA併發

ThreadPoolTaskExecutor的引數:

  int corePoolSize:執行緒池維護執行緒的最小數量. 
  int maximumPoolSize:執行緒池維護執行緒的最大數量. 
  long keepAliveTime:空閒執行緒的存活時間. 
  TimeUnit unit: 時間單位,現有納秒,微秒,毫秒,秒列舉值. 
  BlockingQueue<Runnable> workQueue:持有等待執行的任務佇列. 
  RejectedExecutionHandler handler: 用來拒絕一個任務的執行,有兩種情況會發生這種情況。 
  一是在execute方法中若addIfUnderMaximumPoolSize(command)為false,即執行緒池已經飽和; 
  二是在execute方法中, 發現runState!=RUNNING || poolSize == 0,即已經shutdown,就呼叫ensureQueuedTaskHandled(Runnable command),在該方法中有可能呼叫reject。

 

ThredPoolTaskExcutor的處理流程:

  當池子大小小於corePoolSize,就新建執行緒,並處理請求

  當池子大小等於corePoolSize,把請求放入workQueue中,池子裡的空閒執行緒就去workQueue中取任務並處理

  當workQueue放不下任務時,就新建執行緒入池,並處理請求,如果池子大小撐到了maximumPoolSize,就用RejectedExecutionHandler來做拒絕處理

  當池子的執行緒數大於corePoolSize時,多餘的執行緒會等待keepAliveTime長時間,如果無請求可處理就自行銷燬

  其會優先建立  CorePoolSiz 執行緒, 當繼續增加執行緒時,先放入Queue中,當 CorePoolSiz  和 Queue 都滿的時候,就增加建立新執行緒,當執行緒達到MaxPoolSize的時候,就會丟擲錯 誤 org.springframework.core.task.TaskRejectedException

  另外MaxPoolSize的設定如果比系統支援的執行緒數還要大時,會丟擲java.lang.OutOfMemoryError: unable to create new native thread 異常。

<!-- 非同步執行緒池 -->
    <bean id="threadPool"  
        class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" scope="singleton">   
       <!-- 核心執行緒數  -->   
        <property name="corePoolSize" value="10" />   
        <!-- 最大執行緒數 -->   
        <property name="maxPoolSize" value="50" />   
        <!-- 佇列最大長度 >=mainExecutor.maxSize -->   
        <property name="queueCapacity" value="10" />   
        <!-- 執行緒池維護執行緒所允許的空閒時間 -->   
        <property name="keepAliveSeconds" value="300" />   
        <!-- 執行緒池對拒絕任務(無執行緒可用)的處理策略 -->   
        <property name="rejectedExecutionHandler">   
            <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy"/>   
        </property>   
    </bean>
使用

1,初始化執行緒池

//非同步執行緒池
	@Autowired
	private ThreadPoolTaskExecutor threadPool;
2,線上程池中執行某個執行緒

threadPool.execute(new Runnable() {...});