Java线程池的原理

前言

为什么要用线程池

在一个进程中,线程是一种非常稀缺的资源。频繁地创建或销毁线程也是一个消耗资源的过程,所以用线程池,可以减少以上的过程。
优势:

  1. 线程复用,减少创建和销毁,提高性能
  2. 响应快
  3. 可以统一管理和监控

什么时候用

  1. 任务量大和需要异步
  2. 每个任务处理时间较短

原理

参数

线程池七大参数:

  1. corePoolSize(核心池大小)
  2. maximumPoolSize(最大线程池大小)
  3. keepAliveTime(存活时间)
  4. unit(时间单位)
  5. workQueue(工作队列)
  6. threadFactory(线程工厂)
  7. handler(拒绝策略)

原理图

1.jpg

说明

这里将设定线程池的参数:核心数=2,最大数=3,队列数=5

  1. 如果核心池为空,则有任务进入,马上在核心池中进行
  2. 如果核心池已经满了,则还有任务进入,非核心池将开辟线程进行处理
  3. 如果核心池和非核心池都满了,则还有任务的,进入队列等待
  4. 如果队列也满了,则根据拒绝策略,对想要进入队列的任务进行处理,默认的就是直接报异常
    四个拒绝策略:
    AbortPolicy:
    直接抛异常
java.util.concurrent.RejectedExecutionException: Task com.company.Thread.MyTask@135fbaa4 rejected from java.util.concurrent.ThreadPoolExecutor@45ee12a7

DiscardPolicy:
丢弃任务,但是不抛出异常。

CallerRunsPolicy:
丢弃队列最前面的任务,然后重新提交被拒绝的任务

for (int i = 0; i < 8; i++) {
    try {
        threadPoolExecutor.execute(new MyTask(i));
    }
    catch (Exception e){
        e.printStackTrace();
    }
}
threadPoolExecutor.execute(new MyTask(8));

#######################

pool-1-thread-3--7:done!
pool-1-thread-2--1:done!
pool-1-thread-1--0:done!
pool-1-thread-2--4:done!
pool-1-thread-3--3:done!
pool-1-thread-1--5:done!
pool-1-thread-2--6:done!
pool-1-thread-3--8:done!

可以看出8才是最后提交的,但是却有8的任务完成,其中2不见了,因为2是在队列的最前面。

DiscardOldestPolicy:
调用线程处理该任务

代码分析

构造函数的七大参数

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.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

有四个可选策略

  1. CallerRunsPolicy
  2. AbortPolicy
  3. DiscardPolicy
  4. DiscardOldestPolicy
    默认策略:AbortPolicy()
private static final RejectedExecutionHandler defaultHandler =
    new AbortPolicy();
...
public static class CallerRunsPolicy implements RejectedExecutionHandler 
...
public static class AbortPolicy implements RejectedExecutionHandler
...
public static class DiscardPolicy implements RejectedExecutionHandler
...
public static class DiscardOldestPolicy implements RejectedExecutionHandler
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
...
public void execute(Runnable command) {
    // 命令为空抛异常
    if (command == null)
        throw new NullPointerException();
    // 原子性cas,线程安全
    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);
}

测试

测试代码:

public class threadpool {
    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor threadPoolExecutor =
                new ThreadPoolExecutor(2, 3, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(5), Executors.defaultThreadFactory());
//        ExecutorService e1 = Executors.newCachedThreadPool();
//        ExecutorService e2 = Executors.newFixedThreadPool(10);
//        ExecutorService e3 = Executors.newSingleThreadExecutor();


        for (int i = 0; i < 9; i++) {
            try {
                threadPoolExecutor.execute(new MyTask(i));
            }
            catch (Exception e){
                e.printStackTrace();
            }
        }


        Queue<Runnable> queue = threadPoolExecutor.getQueue();

        for (int i = 0; i < 10; i++) {
            System.out.println("核心数:" + threadPoolExecutor.getCorePoolSize());
            System.out.println("最大数:" + threadPoolExecutor.getMaximumPoolSize());
            System.out.println("池化数:" + threadPoolExecutor.getPoolSize());
            System.out.println("队列数:" + queue.size());
            System.out.println("默认策略:" + threadPoolExecutor.getRejectedExecutionHandler());
            Thread.sleep(60000L);
            System.out.println("*************************************");
        }

        threadPoolExecutor.shutdown();
    }
}

class MyTask implements Runnable{
    int i = 0;

    public MyTask(int i){
        this.i = i;
    }

    @Override
    public void run() {
        try{
            Thread.sleep(60000L);
            System.out.println(Thread.currentThread().getName() + "--" + i + ":done!");
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

以下结果可以看出,在核心池和非核心池都满了,和队列也满的情况下,在加入任务,就会触发拒绝策略,报异常。
每完成一个任务,都将队列的任务往核心池仍,直到队列空了。
结果:

java.util.concurrent.RejectedExecutionException: Task com.company.Thread.MyTask@135fbaa4 rejected from java.util.concurrent.ThreadPoolExecutor@45ee12a7[Running, pool size = 3, active threads = 3, queued tasks = 5, completed tasks = 0]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
	at com.company.Thread.threadpool.main(threadpool.java:17)
核心数:2
最大数:3
池化数:3
队列数:5
默认策略:java.util.concurrent.ThreadPoolExecutor$AbortPolicy@2503dbd3
*************************************
pool-1-thread-1--0:done!
pool-1-thread-2--1:done!
pool-1-thread-3--7:done!
核心数:2
最大数:3
池化数:3
队列数:2
默认策略:java.util.concurrent.ThreadPoolExecutor$AbortPolicy@2503dbd3
pool-1-thread-1--2:done!
*************************************
核心数:2
最大数:3
池化数:3
pool-1-thread-3--4:done!
pool-1-thread-2--3:done!
队列数:1
默认策略:java.util.concurrent.ThreadPoolExecutor$AbortPolicy@2503dbd3
*************************************
核心数:2
最大数:3
pool-1-thread-1--5:done!
pool-1-thread-3--6:done!
池化数:2
队列数:0
默认策略:java.util.concurrent.ThreadPoolExecutor$AbortPolicy@2503dbd3
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值