线程池——JUC随记8
线程池使用方式
1、一池N线程(Executors.newFixedThreadPool(n))
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ExecutorDemo {public static void main(String[] args) {ExecutorService executorService= Executors.newFixedThreadPool(5);try {for (int i = 0; i <10 ; i++) {executorService.execute(()->{System.out.println(Thread.currentThread().getName()+":处理了业务");});}}finally {executorService.shutdown();}}
}
2、一池一线程(Executors.newSingleThreadExecutor())
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ExecutorDemo {public static void main(String[] args) {ExecutorService executorService= Executors.newSingleThreadExecutor();try {for (int i = 0; i <10 ; i++) {executorService.execute(()->{System.out.println(Thread.currentThread().getName()+":处理了业务");});}}finally {executorService.shutdown();}}
}
3、可扩容(Executors.newCachedThreadPool())
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ExecutorDemo {public static void main(String[] args) {ExecutorService executorService= Executors.newCachedThreadPool();try {for (int i = 0; i <30 ; i++) {executorService.execute(()->{System.out.println(Thread.currentThread().getName()+":处理了业务");});}}finally {executorService.shutdown();}}
}
线程池7参数
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.acc = System.getSecurityManager() == null ?null :AccessController.getContext();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;}
(1)corePoolSize:线程池中常驻核心线程数。
(2)maximumPoolSize:线程池能够容纳同时执行的最大线程数,此值必须大于等于1。
(3)keepAliveTime:多余的空闲线程存活时间。当前线程池数量超过corePoolSize时,当空闲时间到达keepAliveTime值时,多余空闲线程会被销毁直到只剩下corePoolSize个线程为止。
(4)unit:keepAliveTime的时间单位。
(5)workQueue:任务(阻塞)队列,被提交但尚未执行的任务。
(6)threadFactory:表示生成线程池中的工作线程的线程工厂,用于创建线程,一般为默认线程工厂即可。
(7)handler:拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时如何来拒绝来请求的Runnable的策略。
线程池的工作流程
当向线程池提交一个任务之后,线程池是如何处理这个任务的呢?本节来看一下线程池
的主要处理流程,处理流程图所示。
从图中可以看出,当提交一个新任务到线程池时,线程池的处理流程如下。
1)线程池判断核心线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作
线程来执行任务。如果核心线程池里的线程都在执行任务,则进入下个流程。
2)线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。
3)线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。
(4)如果已经满了,则交给饱和(拒绝)策略来处理这个任务。
ThreadPoolExecutor执行execute()方法的示意图,如图所示。
拒绝策略
1、AbortPolicy(默认)
直接抛出拒绝异常(继承自RuntimeException),会中断调用者的处理过程,所以除非有明确需求,一般不推荐
2、CallerRunsPolicy
在调用者线程中(也就是说谁把这个任务甩来的),运行当前被丢弃的任务。只会用调用者所在线程来运行任务,也就是说任务不会进入线程池。如果线程池已经被关闭,则直接丢弃该任务。
3、DiscardOledestPolicy
丢弃队列中最老的,然后把当前任务加入到队列中,再次尝试提交新任务。
4、DiscardPolicy
该策略默默地丢弃无法处理的任务.不予任何处理也不抛出异常。如果允许任务丢失.这是最好的一种策略。
5、实现 RejectedExecutionHandler 接口扩展
自定义线程池
import java.util.concurrent.*;public class MyThreadPool {public static void main(String[] args) {ThreadPoolExecutor myThreadPoolExecutor = new ThreadPoolExecutor(2,5,2L,TimeUnit.SECONDS,new ArrayBlockingQueue<>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());try {for (int i = 0; i <30 ; i++) {myThreadPoolExecutor.execute(()->{System.out.println(Thread.currentThread().getName()+":处理了业务");});}}finally {myThreadPoolExecutor.shutdown();}}}