廖雪峰Java11多线程编程-3高级concurrent包-6ExecutorService

匿名 (未验证) 提交于 2019-12-02 21:40:30

Java语言内置多线程支持:

  • 创建线程需要操作系统资源(线程资源,栈空间)
  • 频繁创建和销毁线程需要消耗大量时间

如果可以复用一个线程

线程池:

  • 线程池维护若干个线程,处于等待状态
  • 如果有新任务,就分配一个空闲线程执行
  • 如果所有线程都处于忙碌状态,新任务放入队列等待

ExecutorService

JDK提供了ExecutorService接口表示线程池:

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

常用的ExecutorService:

  • FixedThreadPool:线程数固定
  • CachedThreadPool:线程数根据任务动态调整
  • SingleThreadExecutor:仅单线程执行
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         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(); //结束线程池     } }

        //单个线程         ExecutorService executor = Executors.newSingleThreadExecutor();

        //动态调整的线程池         ExecutorService executor = Executors.newCachedThreadPool();



查看newCachedThreadPool源码,发现其实现的是ThreadPoolExecutor的构造方法,

    public static ExecutorService newCachedThreadPool() {         return new ThreadPoolExecutor(0, //初始化线程池的大小                                       Integer.MAX_VALUE,//线程池的最大值                                       60L, TimeUnit.SECONDS,                                       new SynchronousQueue<Runnable>());     }
        //设置最大数量为10的动态线程池         ExecutorService executor = new ThreadPoolExecutor(0, 10,                 60L, TimeUnit.SECONDS,                 new SynchronousQueue<Runnable>());

执行模式:

  • Fixed Rate:固定的间隔,任务就会执行。例如每隔3秒任务就会启动,而不管这个任务执行多长、是否结束
  • Fixed Delay:当任务执行完毕以后,等待1秒钟再继续执行。无论任务执行多久,只有在任务结束以后,等待1秒钟才会开始执行下一次的任务。
    注意:ScheduledExecutorService不会自动停止
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);         executor.scheduleWithFixedDelay(new HelloTask("Alice"),2,5,TimeUnit.SECONDS);     } }


Bob的执行频率比Alice高的多,任务开始的时间差也越来越大
问题:
1.FixedRate模式下,如果任务执行时间过长,后续任务会不会并发执行?


不会

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(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);      } }


2.如果任务抛出了异常,后续任务是否继续执行?
不会

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);     } }

  • 一个Timer对应一个Thread,只能定期执行一个任务。如果要执行多个定时任务,就必须要启动多个Timer。
  • 必须在主线程结束时跳用Timer.cancel()
    而一个ScheduledPool就可以调度多个任务,所以完全可以用新的Scheduled取代Timer类。
  • JDK提供了ExecutorService实现了线程池功能
  • 线程池内部维护一组线程,可以搞笑执行大量小任务
  • Executors提供了静态方法创建不同类型的ExecutorService
  • 必须调用shutdown()关闭ExecutorService
  • ScheduledThreadPool可以定期调度多个任务
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!