1.线程池的状态 ThreadPoolExecutor使用int的高三位表示线程池的状态,低29为表示线程数量。
状态名称
高3位的值
描述
RUNNING
111
接收新任务,同时处理任务队列中的任务
SHUTDOWN
000
不接受新任务,但是处理任务队列中的任务
STOP
001
中断正在执行的任务,同时抛弃阻塞队列中的任务
TIDYING
010
任务执行完毕,活动线程为0时,即将进入终结阶段
TERMINATED
011
终结状态
高三位111表示的是负数:- 3
1 2 3 4 5 6 7 private static final int COUNT_BITS = 29 ;private static final int COUNT_MASK = 536870911 ;private static final int RUNNING = -536870912 ;private static final int SHUTDOWN = 0 ;private static final int STOP = 536870912 ;private static final int TIDYING = 1073741824 ;private static final int TERMINATED = 1610612736 ;
线程池状态和线程池中线程的数量由一个原子整型ctl来共同表示
2.构造方法 2.1 最全的 1 2 3 4 5 6 7 public ThreadPoolExecutor (int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
corePoolSize:核心线程数
maximumPoolSize:最大线程数
maximumPoolSize - corePoolSize = 救急线程数
keepAliveTime:救急线程空闲时的最大生存时间
unit:时间单位
workQueue:阻塞队列(存放任务)
有界阻塞队列 ArrayBlockingQueue
无界阻塞队列 LinkedBlockingQueue
最多只有一个同步元素的 SynchronousQueue
优先队列 PriorityBlockingQueue
threadFactory:线程工厂(给线程取名字)
handler:拒绝策略
救急线程 就是当核心线程都在处理任务,并且阻塞队列里已经满了的时候,如果再来一个任务,急救线程就会被创建,来处理这个任务,当超过救急线程空闲时的最大生存时间,它会被释放。(当阻塞队列有容量限制时才可以使用救急线程)
拒绝策略 :如果线程到达 maximumPoolSize 仍然有新任务这时会执行拒绝策略 。拒绝策略 jdk 提供了 4 种实现
AbortPolicy:让调用者抛出 RejectedExecutionException 异常,这是默认策略
CallerRunsPolicy:让调用者运行任务
DiscardPolicy:放弃本次任务
DiscardOldestPolicy:放弃队列中最早的任务,本任务取而代之
2.2 newFixedThreadPool 1 2 3 public static ExecutorService newFixedThreadPool (int nThreads) { return new ThreadPoolExecutor (nThreads, nThreads, 0L , TimeUnit.MILLISECONDS, new LinkedBlockingQueue ()); }
用法:
1 ExecutorService pool = Executors.newFixedThreadPool(2 );
1 2 3 public static ExecutorService newFixedThreadPool (int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor (nThreads, nThreads, 0L , TimeUnit.MILLISECONDS, new LinkedBlockingQueue (), threadFactory); }
这个方法可以给线程起名字。
2.3 newCachedThreadPool 1 2 3 public static ExecutorService newCachedThreadPool () { return new ThreadPoolExecutor (0 , 2147483647 , 60L , TimeUnit.SECONDS, new SynchronousQueue ()); }
用法:
1 ExecutorService pool = Executors.newCachedThreadPool();
没有核心线程,最大线程数为Integer.MAX_VALUE,所有创建的线程都是救急线程 ,空闲时生存时间为60秒
2.4 newSingleThreadExecutor 1 2 3 public static ExecutorService newSingleThreadExecutor () { return new Executors .FinalizableDelegatedExecutorService(new ThreadPoolExecutor (1 , 1 , 0L , TimeUnit.MILLISECONDS, new LinkedBlockingQueue ())); }
用法
1 ExecutorService pool = Executors.newSingleThreadExecutor();
线程数固定为1,不能修改,没有急救线程,当任务数多于1时会放入无界队列排队,任务执行完毕这个线程也不会释放。
3.提交任务
4.定时执行任务 1 2 3 public static ScheduledExecutorService newScheduledThreadPool (int corePoolSize) { return new ScheduledThreadPoolExecutor (corePoolSize); }
4.1 schedule() 1 2 3 4 5 6 pool.schedule(()->{ System.out.println("任务1执行..." ); }, 1 , TimeUnit.SECONDS); pool.schedule(()->{ System.out.println("任务2执行..." ); }, 1 , TimeUnit.SECONDS);
(无论核心线程数是1还是更多)一旦第一个任务执行受到了异常,第二个任务也不会受到影响,还是会被执行。
4.2 scheduleAtFixedRate() 1 pool.scheduleAtFixedRate(()->{},1 ,1 ,TimeUnit.SECONDS);
以固定速率执行任务
第一个参数是任务对象,第二个参数是针对当前时间来说,延时的时间
(主线程调用这个方法后,多长时间后才开始工作),第三个参数是执行间隔(每隔这么长时间就执行一次任务,一直执行)
当一个任务的执行时间超过了执行间隔,就等这个任务执行完后立刻执行下一个任务,不会让任务重叠。
假如每个任务执行需要耗时2s,执行间隔是1s,明显已经超过了执行间隔,每个任务之间的时间是2s,就是任务执行时间。
4.3 scheduleWithFixedDelay() 1 pool.scheduleWithFixedDelay(() -> {},1 ,1 ,TimeUnit.SECONDS);
第三个参数是执行间隔(这个是真正的间隔,严格意义上每个任务之间都必须有这个间隔时间),其他的参数和上面的那个方法一样
假如每个任务执行需要耗时2s,再加上执行间隔1s,每个任务之间的时间是3s
5.结束任务 5.1 shutdown() 线程池状态变为SHUTDOWN
,不会接收新任务, 但已经提交的任务(在阻塞队列中)会执行完,调用这个方法的线程在运行完这一行会继续往后执行,不会等待线程全部SHUTDOWN之后再往后执行。
1 2 ExecutorService pool = Executors.newFixedThreadPool(2 ); pool.shutdown();
5.2 shutdownNow() 线程池状态变为STOP
,不会接收新任务,会将队列中的任务返回,不再执行,并用interrupt的方式中断正在执行的线程。(夺笋那)