六、线程池(一) (2)

通常在创建线程池时不指定此参数,它会使用默认的线程创建工厂的方法来创建线程,源代码如下:

public ThreadPoolExecutor(int corePoolSize,                           int maximumPoolSize,                           long keepAliveTime,                           TimeUnit unit,                           BlockingQueue<Runnable> workQueue) {     // Executors.defaultThreadFactory() 为默认的线程创建工厂     this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,          Executors.defaultThreadFactory(), defaultHandler); } public static ThreadFactory defaultThreadFactory() {     return new DefaultThreadFactory(); } // 默认的线程创建工厂,需要实现 ThreadFactory 接口 static class DefaultThreadFactory implements ThreadFactory {     private static final AtomicInteger poolNumber = new AtomicInteger(1);     private final ThreadGroup group;     private final AtomicInteger threadNumber = new AtomicInteger(1);     private final String namePrefix;     DefaultThreadFactory() {         SecurityManager s = System.getSecurityManager();         group = (s != null) ? s.getThreadGroup() :                               Thread.currentThread().getThreadGroup();         namePrefix = "pool-" +                       poolNumber.getAndIncrement() +                      "-thread-";     }     // 创建线程     public Thread newThread(Runnable r) {         Thread t = new Thread(group, r,                               namePrefix + threadNumber.getAndIncrement(),                               0);         if (t.isDaemon())              t.setDaemon(false); // 创建一个非守护线程         if (t.getPriority() != Thread.NORM_PRIORITY)             t.setPriority(Thread.NORM_PRIORITY); // 线程优先级设置为默认值         return t;     } }

RejectedExecutionHandler

表示指定线程池的拒绝策略,当线程池的任务已经在缓存队列 workQueue 中存储满了之后,并且不能创建新的线程来执行此任务时,就会用到此拒绝策略.

它属于一种限流保护的机制,这里有四种任务拒绝类型:

AbortPolicy: 不执行新任务,直接抛出异常,提示线程池已满,涉及到该异常的任务也不会被执行,线程池默认的拒绝策略就是该策略。

DisCardPolicy: 不执行新任务,也不抛出异常,即忽略此任务;

DisCardOldSetPolicy: 将消息队列中的第一个任务(即等待时间最久的任务)替换为当前新进来的任务执行,忽略最早的任务(最先加入队列的任务);

CallerRunsPolicy: 把任务交给当前线程来执行;

/** * 线程池的拒绝策略 */ @Test public void test1() { // 创建线程池 核心线程为1,最大线程为3,任务队列大小为2 ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(1, 3, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(2), new ThreadPoolExecutor.AbortPolicy() // 添加 AbortPolicy 拒绝策略 ); for (int i = 0; i < 6; i++) { poolExecutor.execute(() -> { System.out.println(Thread.currentThread().getName()); }); } }

自定义线程池拒绝策略

/** * 自定义线程池的拒绝策略 * 实现接口 RejectedExecutionHandler */ @Test public void test2() { ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 3, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(2), new RejectedExecutionHandler() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { // 业务处理方法 System.out.println("执行自定义拒绝策略"); } } ); for (int i = 0; i < 6; i++) { executor.execute(() -> { System.out.println(Thread.currentThread().getName()); }); } }

线程池工作原理

线程池工作原理

线程池的工作流程要从它的执行方法 execute() 说起,源码如下:

public void execute(Runnable command) {     if (command == null)         throw new NullPointerException();     int c = ctl.get();     // 当前工作的线程数小于核心线程数     if (workerCountOf(c) < corePoolSize) {         // 创建新的线程执行此任务         if (addWorker(command, true))             return;         c = ctl.get();     }     // 检查线程池是否处于运行状态,如果是则把任务添加到队列     if (isRunning(c) && workQueue.offer(command)) {         int recheck = ctl.get();         // 再出检查线程池是否处于运行状态,防止在第一次校验通过后线程池关闭         // 如果是非运行状态,则将刚加入队列的任务移除         if (! isRunning(recheck) && remove(command))             reject(command);         // 如果线程池的线程数为 0 时(当 corePoolSize 设置为 0 时会发生)         else if (workerCountOf(recheck) == 0)             addWorker(null, false); // 新建线程执行任务     }     // 核心线程都在忙且队列都已爆满,尝试新启动一个线程执行失败     else if (!addWorker(command, false))          // 执行拒绝策略         reject(command); }

execute() VS submit()

execute() 和 submit() 都是用来执行线程池任务的,它们最主要的区别是,submit() 方法可以接收线程池执行的返回值,而 execute() 不能接收返回值。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpgfyg.html