JavaSE(24)——线程池详解

线程池详解

1. 线程池的意义

线程是稀缺资源,它的创建与销毁是比较重且耗资源的操作。而Java线程依赖于内核线程,创建线程需要进行操作系统状态切换,为避免资源过度消耗需要设法重用线程执行多个任务,线程池就是一个线程缓存,负责对线程进行统一分配,调优与监控。

线程池的优势

  • 重用存在的线程,减少线程创建、消亡的开销,提高性能
  • 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行任务。
  • 提高线程的可管理性。线程是稀缺资源,如果无限制创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

2. 线程池的创建

  1. Executors.newFixedThreadPool()
              newWorkStealingPool()
              newSingleThreadExecutor()
              newCachedThreadPool()
              newScheduledThreadPool()
    

    (极不推荐)通过Executors的静态方法初始化线程池

  2. ThreadPoolExecutor(
        int corePoolSize,
        int maximumPoolSize,
        long keepAliveTime,
        TimeUnit unit,
        BlockingQueue<Runnable> workQueue
    )
    

    推荐使用,可以自定义线程池的参数。以下线程池也都指该类。

3. ThreadPoolExecutor 源码

3.1 源码注释

  1. 使用线程池的线程来完成任务,一般使用Executors工厂方法来配置
  2. 线程池一般用来解决两个好处
    1. 线程重复利用,减少创建线程个数,提高性能
    2. 提供限定和管理资源的手断
  3. 该类提供了很好的拓展性,但一般我们使用Executors工厂方法就可以创建出三种非常好用的线程池了
  4. 自定义线程池
    1. 如果运行的线程少于corePoolSize,则创建新线程来处理请求,即使其他辅助线程是空闲的
    2. 如果运行的线程大于corePoolSize,小于maximumPoolSize,则仅当队列满时才创建新线程
    3. 如果设置的corePoolSize和maximumPoolSize相同,则创建了固定大小的线程池
    4. 如果设置了maximumPoolSize最大值,那么允许池适应任意数量的并发任务

3.2 属性

//使用原子类Integer存储线程池属性
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//高3位存储运行状态
private static final int COUNT_BITS = Integer.SIZE - 3;
//后29位存储容量
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

//111=RUNNING
private static final int RUNNING    = -1 << COUNT_BITS;
//000=SHUTDOWN
private static final int SHUTDOWN   =  0 << COUNT_BITS;
//001=STOP
private static final int STOP       =  1 << COUNT_BITS;
//010=TIDYING
private static final int TIDYING    =  2 << COUNT_BITS;
//011=TERMINATED
private static final int TERMINATED =  3 << COUNT_BITS;

//获取运行状态,ctl & (1110 ...)
private static int runStateOf(int c)     { return c & ~CAPACITY; }
//获取容量,ctl & (0001 1111...)
private static int workerCountOf(int c)  { return c & CAPACITY; }
//将运行状态和池容量做或运算,得出ctl
private static int ctlOf(int rs, int wc) { return rs | wc; }

线程池的状态:

  • RUNNING:线程池能够接受新任务,以及对新添加的任务进行处理
  • SHUTDOWN:线程池不可以接受新任务,但是可以对已添加的任务进行处理
  • STOP:线程池不接受新任务,不处理已添加的任务,并且会中断当前正在处理的任务
  • TIDYING:当所有的任务已终止,ctl记录的“任务数量”为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated。terminated在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的数量,可以通过重载terminated函数来实现
  • TERMINATED:线程池彻底终止的状态

3.3 默认实现的池

  1. new FixedThreadPool

    一个固定线程数的线程池,返回一个corePoolSize和maximumPoolSize相等的线程池

  2. newCachedThreadPool

    非常有弹性的线程池,对于新的任务,如果此时线程池里没有空闲线程,线程池会毫不犹豫地创建一条新的线程去处理这个任务。

  3. SingleThreadExecutor

    使用单个worker线程

  4. ScheduledThreadPoolExecutor

    可以用来在给定延时后执行异步任务或者周期性执行任务

  5. ForkJoinPool

    ForkJoinPool 最适合的是计算密集型的任务,如果存在 I/O,线程间同步,sleep() 等会造成线程长时间阻塞的情况时,最好配合使用 ManagedBlocker。

    newWorkStealingPool就是ForkJoinPool的实现类

3.4 方法

  • 构造方法

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {}
    
    1. corePoolSize			指定核心线程数量
    2. maximumPoolSize   	指定最大线程数量
    3. keepAliveTime     	允许线程空闲时间
    4. unit              	时间对象
    5. workQueue          	阻塞队列
    6. threadFactory    	线程工厂
    7. handler            	任务拒绝策略
    
    1. 线程数量要点

      • 如果运行线程的数量少于核心线程数量,则创建新的线程处理请求
      • 如果运行线程的数量大于核心线程数量,小于最大线程数量,则当队列满的时候才创建新的线程
      • 如果核心线程数量等于最大线程数量,那么将创建固定大小的连接池
      • 如果设置了最大线程数量为无穷,那么允许线程池适合任意的并发数量
    2. 线程空闲时间要点:

      • 当前线程数大于核心线程数,如果空闲时间已经超过了,那该线程会销毁
    3. 排队策略要点

      • 同步移交:不会放到队列中,而是等待线程执行它。如果当前线程没有执行,很可能会新开一个线程执行。
      • 无界限策略:如果核心线程都在工作,该线程会放到队列中。所以线程数不会超过核心线程数
      • 有界限策略:可以避免资源耗尽,但是一定程度上减低了吞吐量

      当线程关闭或者线程数量满了和队列饱和了,就有拒绝任务的情况了:

    4. 拒绝任务策略:

      • 直接抛出异常
      • 直接丢掉这个任务
      • 丢掉最老的任务
      • 使用调用者的线程来处理
  • 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();
            //当线程池不属于Running状态时,删除线程
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        //核心线程和队列都满,尝试添加线程
        else if (!addWorker(command, false))
            reject(command);
    }
    
    private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
    		
            //当运行状态不为Running时,或者处于shutdown,stop,tiyding,terminated时,返回false
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;
    
            for (;;) {
                int wc = workerCountOf(c);
                
                //线程数大于容量,或者大于核心线程池或最大线程池大小时,返回false
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                //更新线程池线程数量
                if (compareAndIncrementWorkerCount(c))
                    break retry;//跳出循环
                c = ctl.get();  // Re-read ctl
                //数据不同步时,重新循环
                if (runStateOf(c) != rs)
                    continue retry;
            }
        }
    
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            //创建一个Worker对象
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                //获取主线程锁
                mainLock.lock();
                
                //更新workers(HashSet)
                try {
                    int rs = runStateOf(ctl.get());
    
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                
                //更新成功则开启线程
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            //启动不成功则删除线程
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }
    
    //向队列中添加
    public boolean offer(E e) {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            if (count == items.length)
                return false;
            else {
                enqueue(e);
                return true;
            }
        } finally {
            lock.unlock();
        }
    }
    
  • shutdown()

    //不再接受新任务,按队列中的顺序,将已有线程执行完毕
    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            //设置线程池状态为Shutdown
            advanceRunState(SHUTDOWN);
            //向线程发出中断请求
            interruptIdleWorkers();
            //钩子函数
            onShutdown(); 
        } finally {
            mainLock.unlock();
        }
        //尝试终止
        tryTerminate();
    }
    
  • shutdownNow()

    //不再接受新的任务和队列中的任务,且将当前线程中断
    //返回等待任务的队列
    public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(STOP);
            interruptWorkers();
            tasks = drainQueue();
        } finally {
            mainLock.unlock();
        }
        //尝试终止
        tryTerminate();
        return tasks;
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值