多线程:线程池原理

1、基础

(1)线程模型的分类

  用户线程(ULT)。用户程序实现,不依赖操作系统核心,应用提供创建、同步、调度和管理线程的函数来控制用户线程。不需要用户态/核心态切换,速度快。内核对ULT无感知,线程阻塞则进程〈包括它的所有线程)阻塞。
  内核线程(KLT),系统内核管理线程(KLT),内核保存线程的状态和上下文信息,线程阻塞不会引起进程阻塞。在多处理器系统上,多线程在多处理器上并行运行。线程的创建、调度和管理由内核完成,效率比ULT要慢,比进程操作快。

(2)java线程与内核线程的关系

jvm运用的是内核级线程模型,java线程与内核线程是一对一的关系

 (2)Executor框架

2、线程池的五种状态

(1)五种状态

  • Running:能接受新任务以及处理已添加的任务
  • Shutdown:不接受新任务,可以处理已经添加的任务
  • Stop:不接受新任务,不处理已经添加的任务,并且中断正在处理的任务
  • Tidying:所有的任务已经终止, ctl记录的”任务数量”为0 ctl负责记录线程池的运行状态与活动线程数量
  • Terminated:线程池彻底终止,则线程池转变为terminated状态

(2)流程

(3)源码(保证线程的安全,将线程池的所有状态保存到一个变量中)

Interger类型的变量的解析:

3、线程池工作原理

(1)五种创建方式

  • newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需求可灵活回收空闲线程,若无可回收,则新建线程
  • newFixedThreadPool:创建一个定长线程池,可控制线程的最大并发数,超出的线程会在线程池中等待。
  • newScheduleThreadPool:创建一个定长线程池,支持定时及周期性任务处理
  • newSingleThreadScheduledExecutor:创建一个单线程化的线程池,他只用唯一的工作栈来执行任务,一池一线程
  • newSingleThreadExecutor):串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

直接使用Executors创建线程的话,线程的数量没有上限,因此需要手动创建线程池

(2)源码ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,//核心线程池的大小
                              int maximumPoolSize,//最大线程数量
                              long keepAliveTime,//线程最长可以空闲多久
                              TimeUnit unit,//时间单位
                              BlockingQueue<Runnable> workQueue,//阻塞队列,在任意时刻不管并发有多高,永远只有一个线程能够进行队列的入队或者出队操作!

                               队列满,只能进行出队操作,所有入队的操作必须等待,也就是被阻塞
                               队列空,只能进行入队操作,所有出队的操作必须等待,也就是被阻塞


ThreadFactory threadFactory) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler); }

  流程:

4、execute方法

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
        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);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))//最大线程数没有执行成功就会触发拒绝策略
            reject(command);
    }

下面代码的ctl是和下面代码片段的ctl联系的:

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    private static final int COUNT_BITS = Integer.SIZE - 3;
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

    // runState is stored in the high-order bits
    private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;

将线程池的所有状态保存到一个Integer类型的变量中去,保证线程的安全。

每个人都会有一段异常艰难的时光 。 生活的压力 , 工作的失意 , 学业的压力。 爱的惶惶不可终日。 挺过来的 ,人生就会豁然开朗。 挺不过来的 ,时间也会教你 ,怎么与它们握手言和 ,所以不必害怕的。 ——杨绛
原文地址:https://www.cnblogs.com/zhai1997/p/13655762.html