廖雪峰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能够按期调度多个任务
相关文章
相关标签/搜索