廖雪峯Java11多線程編程-3高級concurrent包-6ExecutorService

1. 線程池

Java語言內置多線程支持:java

  • 建立線程須要操做系統資源(線程資源,棧空間)
  • 頻繁建立和銷燬線程須要消耗大量時間

假設咱們有大量的小任務,可讓它排隊執行,而後在一個線程池裏有少許的線程來執行大量的任務。 使用線程池來複用線程,能夠很是高效的執行大量小任務。 <img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190613195010587-628000334.png" width="500" /> <strong>線程池:</strong>多線程

  • 線程池維護若干個線程,處於等待狀態
  • 若是有新任務,就分配一個空閒線程執行
  • 若是全部線程都處於忙碌狀態,新任務放入隊列等待

2. ExecutorService

JDK提供了ExecutorService接口表示線程池:併發

ExecutorService executor = Executors.newFixedThreadPool(4); //固定大小的線程池
    executor.submit(task1); //提交任務到線程池
    executor.submit(task2);
    executor.submit(task3)

經常使用的ExecutorService:this

  • FixedThreadPool:線程數固定
  • CachedThreadPool:線程數根據任務動態調整
  • SingleThreadExecutor:僅單線程執行

2.1 FixedThreadPool示例

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

class PrintTask implements Runnable{
    String name;
    public PrintTask(String name){
        this.name = name;
    }
    public void run(){
        for(int i=0;i<3;i++){
            System.out.println(i+" Hello,"+name+"!");
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){}
        }
    }
}
public class ThreadPool {
    public static void main(String[] args) throws InterruptedException{
        ExecutorService executor = Executors.newFixedThreadPool(3); //指定線程池大小爲3,提供了4個任務,會有1個任務等待有空閒線程後執行。
        executor.submit(new PrintTask("Bob"));
        executor.submit(new PrintTask("Alice"));
        executor.submit(new PrintTask("Tim"));
        executor.submit(new PrintTask("Robot"));
        Thread.sleep(10000);
        executor.shutdown(); //結束線程池
    }
}

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190613201653559-1979756267.png" width="500" /> ### 2.2 SingleThreadExecutor示例 ```#java //單個線程,全部的任務將串行執行 ExecutorService executor = Executors.newSingleThreadExecutor(); ``` <img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190613201906374-1166857837.png" width="500" /> ### 2.3 CachedThreadPool示例 ```#java //動態調整的線程池。因爲CachedThreadPool會根據咱們的任務,動態的調整線程的數量,因此這個任務提交後,線程池會馬上建立4個線程來執行它。 ExecutorService executor = Executors.newCachedThreadPool(); ``` <img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190613202141684-2034032425.png" width="500" /> ### 2.4 動態線程池指定最大線程數量 若是咱們想要限制動態線程池中線程的上限,例如最多10個線程,這個時候,CachedThreadPool就不可以知足這個要求。 查看newCachedThreadPool源碼,發現其實現的是ThreadPoolExecutor的構造方法, ```#java public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor( 0, //初始化線程池的大小 Integer.MAX_VALUE, //線程池的最大值 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } public ThreadPoolExecutor( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue ) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); } ``` 示例 ```#java //設置最大數量爲10的動態線程池 ExecutorService executor = new ThreadPoolExecutor(0, 10, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); ```spa

3. ScheduledThreadPool

JDK還提供了ScheduledThreadPool,使一個任務能夠按期反覆執行。 執行模式:操作系統

  • Fixed Rate:在固定的間隔,任務就會執行。例如每隔3秒任務就會啓動,而無論這個任務已執行了多長時間、是否結束
  • Fixed Delay:當任務執行完畢之後,等待1秒鐘再繼續執行。不管任務執行多久,只有在任務結束之後,等待1秒鐘纔會開始執行下一次的任務。

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190613212212816-656274626.png" width="500" />線程

<font color=#FF0000>注意:ScheduledThreadPool不會自動中止,須要手動強制結束。</font>code

3.1示例

import java.time.LocalTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

class HelloTask implements Runnable{
    String name;
    public HelloTask(String name){
        this.name = name;
    }
    public void run(){
        System.out.println("Hello,"+name+" ! It is "+LocalTime.now());
        try{
            Thread.sleep(1000);
        }catch (InterruptedException e){}
        System.out.println("Goodbye, "+name+"! It is "+LocalTime.now());
    }

}
public class SchedulePool {
    public static void main(String[] args) throws Exception{
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
        executor.scheduleAtFixedRate(new HelloTask("Bob"),2,5,TimeUnit.SECONDS); //2秒之後開始執行,每5秒就執行這個任務
        executor.scheduleWithFixedDelay(new HelloTask("Alice"),2,5,TimeUnit.SECONDS); //2秒之後開始執行,執行結束等待5秒再執行
    }
}

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190613213102401-328447006.png" width="500" /> Bob的執行頻率比Alice高的多,任務開始的時間差也愈來愈大 <font color=#FF0000>問題: <strong>1.FixedRate模式下,若是任務執行時間過長,後續任務會不會併發執行?</strong></font> <img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190613213435667-1820358537.png" width="500" /> <font color=#458B00>不會</font> ```#java import java.time.LocalTime; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit;blog

class HelloTask implements Runnable{ String name; public HelloTask(String name){ this.name = name; } public void run(){ System.out.println("Hello,"+name+" ! It is "+LocalTime.now()); try{ Thread.sleep(10000); }catch (InterruptedException e){} System.out.println("Goodbye, "+name+"! It is "+LocalTime.now()); }接口

} public class SchedulePool { public static void main(String[] args) throws Exception{ ScheduledExecutorService executor = Executors.newScheduledThreadPool(3); executor.scheduleAtFixedRate(new HelloTask("Bob"),2,1,TimeUnit.SECONDS);

}

}

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190613214419984-1491212580.png" width="500" />
<font color=#FF0000><strong>2.若是任務拋出了異常,後續任務是否繼續執行?</strong></font>
<font color=#458B00>不會</font>
```#java
import java.time.LocalTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

class HelloTask implements Runnable{
    String name;
    int count;
    public HelloTask(String name,int count){
        this.name = name;
        this.count = count;
    }
    public void run(){
        System.out.println("Hello,"+name+" ! It is "+LocalTime.now()+" "+count);
        try{
            if(count == 3){
                throw new RuntimeException("我是故意的");
            }
            Thread.sleep(1000);
        }catch (InterruptedException e){}
        System.out.println("Goodbye, "+name+"! It is "+LocalTime.now());
        count++;
    }

}
public class SchedulePool {
    public static void main(String[] args) throws Exception{
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
        executor.scheduleAtFixedRate(new HelloTask("Bob",0),2,5,TimeUnit.SECONDS);
    }
}

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190613215335169-975948766.png" width="500" />

4. java.util.Timer

jdk還提供了java.util.Timer類,這個類也能夠按期執行一個任務:

  • 一個Timer對應一個Thread,只能按期執行一個任務。若是要執行多個定時任務,就必需要啓動多個Timer。
  • 必須在主線程結束時跳用Timer.cancel()

<font color=#458B00><strong>而一個ScheduledPool就能夠調度多個任務,因此徹底能夠用新的Scheduled取代Timer類。</strong></font>

5. 總結:

  • JDK提供了ExecutorService實現了線程池功能
  • 線程池內部維護一組線程,能夠搞笑執行大量小任務
  • Executors提供了靜態方法建立不一樣類型的ExecutorService
  • 必須調用shutdown()關閉ExecutorService
  • ScheduledThreadPool能夠按期調度多個任務
相關文章
相關標籤/搜索