Java并发-线程池

Java并发-线程池

线程池简介

如果是一个任务创建一个线程,存在以下问题:

解决以上问题的思路是:

线程池的其他好处:

线程池构造函数的参数

参数名类型含义
corePoolSizeint核心线程数
maxPoolSizeint最大线程数
keepAliveTimelong超出核心线程数的空闲线程存活时间
workQueueBlockingQueue任务存储队列
threadFactoryThreadFactory当线程池需要新的线程的时候,会使用threadFactory来生成新的线程
HandlerRejectedExecutionHandler由于线程池无法接受所提交的任务,采取的拒绝策略

keepAliveTime

如果线程池当前的线程数多于corePoolSize,那么如果多余的线程空闲时间超过keepAliveTime,他们就会被终止

工作队列 workQueue

有三种最常见的队列类型:

线程工厂 ThreadFactory

新的线程是由ThreadFactory创建的,默认会用Exectors.defaultThreadFactory(),创建出来的线程都在同一个线程组,拥有同样的NORM_PRIORITY优先级并且都不是守护线程。如果自己指定ThreadFactory,那么就可以改变线程名,线程组,优先级,是否是守护线程等。

拒绝策略 Handler

拒绝时机:

4种拒绝策略

线程的添加规则

  1. 如果线程数小于corePoolSize,即使其他工作线程处于空闲状态,也会创建一个新线程来运行任务。
  2. 如果线程数等于或大于corePoolSize,则将任务放入workQueue
  3. 如果workQueue已满,并且线程数小于maxPoolSize,则创建一个新线程来运行任务。
  4. 如果workQueue已满,并且线程数大于或等于maxPoolSize,则使用提供的拒绝策略来拒绝该任务。
    线程添加规则流程图.png

可以看出,线程池趋于保持较少的线程数,只有在负载变得很大时才增加线程数。

JDK提供的几种常见线程池

ParameterFixedThreadPoolCachedThreadPoolScheduledThreadPoolSingleThreadExector
corePoolSize由参数决定0由参数决定1
maxPoolSize和corePollSize相等Integer.MAX_VALUEInteger.MAX_VALUE1
keepAliveTime060秒60s0
blockingQueueLinkedBlockingQueueSynchronousQueueDelayedWorkQueueLinkedBlockingQueue

其中DelayWorkQueue是基于小顶堆实现的队列,也是一个无限队列,因此,ScheduledThreadPool的参数maxPoolSize = Integer.MAX_VALUE实际上是无意义的。
ScheduledThreadPool实现了ScheduledExecutorService接口,接口中包括三个方法:

线程池的钩子方法

ThreadPoolExecutor提供了3个钩子方法,需要子类根据需要重写方法

Exector的继承关系

Exector继承关系.png

线程池中线程复用原理

    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            // 当传入的任务不为空或者从工作队列中取出的任务不为空时,就循环复用这个线程
            while (task != null || (task = getTask()) != null) {
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

线程池的状态

RUNNING接受新任务并处理排队任务
SHUTDOWN不接受新任务,但处理排队任务
STOP不接受新任务,也不处理排队任务,并终端正在进行的任务
TIDYING所有任务都已终止,workerCount为零时,线程会转换为TIDYING状态,并将执行terminate()钩子方法
TERMINATEDterminnate()运行完成

停止线程池的方法

shutdown

想线程池发出关闭线程的指令,此时新任务想要进入线程池将被拒绝;线程池不会立即关闭,线程池会在将当前线程中的任务以及工作队列中的任务全部执行完毕后才进入Terminated,但是当收到shutdown指令是,线程池进入shutdown状态。

shutdownNow

shutdownNow方法用于直接中断线程池中的所有任务,包括线程中正在进行的任务以及工作队列中等待的任务,方法有一个返回值List,List中包含工作队列中等待的任务

isShutdown

判断线程池是否处于shutdown状态

isTerminated

判断线程是否处于terminated状态