线程池创建方式

1.注意:Executors是不建议的

2.强制使用ThreadPoolExecutor

2.1

点击查看代码
public ThreadPoolExecutor(int corePoolSize,
            int maximumPoolSize,
            long keepAliveTime,
            TimeUnit unit,
            BlockingQueue<Runnable> workQueue,
            ThreadFactory threadFactory,
            RejectedExecutionHandler handler)

其中的参数含义是:

corePoolSize:线程池中的线程数量;
maximumPoolSize:线程池中的最大线程数量;
keepAliveTime:当线程池线程数量超过corePoolSize时,多余的空闲线程会在多长时间内被销毁;
unit:keepAliveTime的时间单位;
workQueue:任务队列,被提交但是尚未被执行的任务;
threadFactory:线程工厂,用于创建线程,一般情况下使用默认的,即Executors类的静态方法defaultThreadFactory();handler:拒绝策略。当任务太多来不及处理时,如何拒绝任务。
对于这些参数要有以下了解:

COREPOOLSIZE与MAXIMUMPOOLSIZE的关系
首先corePoolSize肯定是 <= maximumPoolSize。

其他关系如下:
若当前线程池中线程数 < corePoolSize,则每来一个任务就创建一个线程去执行;
若当前线程池中线程数 >= corePoolSize,会尝试将任务添加到任务队列。如果添加成功,则任务会等待空闲线程将其取出并执行;
若队列已满,且当前线程池中线程数 < maximumPoolSize,创建新的线程;
若当前线程池中线程数 >= maximumPoolSize,则会采用拒绝策略(JDK提供了四种,下面会介绍到)。

workQueue

参数workQueue是指提交但未执行的任务队列。若当前线程池中线程数>=corePoolSize时,就会尝试将任务添加到任务队列中。主要有以下几种:

SynchronousQueue:直接提交队列。SynchronousQueue没有容量,所以实际上提交的任务不会被添加到任务队列,总是将新任务提交给线程执行,如果没有空闲的线程,则尝试创建新的线程,如果线程数量已经达到最大值(maximumPoolSize),则执行拒绝策略。
LinkedBlockingQueue:无界的任务队列。当有新的任务来到时,若系统的线程数小于corePoolSize,线程池会创建新的线程执行任务;当系统的线程数量等于corePoolSize后,因为是无界的任务队列,总是能成功将任务添加到任务队列中,所以线程数量不再增加。若任务创建的速度远大于任务处理的速度,无界队列会快速增长,直到内存耗尽。

handler

JDK内置了四种拒绝策略:

DiscardOldestPolicy策略:丢弃任务队列中最早添加的任务,并尝试提交当前任务;
CallerRunsPolicy策略:调用主线程执行被拒绝的任务,这提供了一种简单的反馈控制机制,将降低新任务的提交速度。
DiscardPolicy策略:默默丢弃无法处理的任务,不予任何处理。
AbortPolicy策略:直接抛出异常,阻止系统正常工作。
至此,我们直接new ThreadPoolExecutor类就不用慌了!!!!

3.如何合理配置线程池的大小

一般需要根据任务的类型来配置线程池大小:
如果是CPU密集型任务,就需要尽量压榨CPU,参考值可以设为 NCPU+1
如果是IO密集型任务,参考值可以设置为2*NCPU
当然,这只是一个参考值,具体的设置还需要根据实际情况进行调整,比如可以先将线程池大小设置为参考值,再观察任务运行情况和系统负载、资源利用率来进行适当调整。

4.代码案例

点击查看代码
public class MyThread implements Runnable {

    private int threadCount;

    public MyThread(int threadCount) {
        this.threadCount = threadCount;
    }

    @Override
    public void run() {
        System.out.println("正在执行task " + threadCount);
        try {
            Thread.currentThread().sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("task " + threadCount + "执行完毕");
    }

点击查看代码
public class ThreadTest {

    public static void main(String[] args) {
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(2, 11, 200, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(50000));


        for (int i = 0; i < 100; i++) {
            MyThread myThread = new MyThread(i);
            poolExecutor.execute(myThread);
            System.out.println("线程池中线程数目:" + poolExecutor.getPoolSize() + "队列中等待执行的任务数目:" + poolExecutor.getQueue().size() + "已执行结束的任务数目:" + poolExecutor.getCompletedTaskCount());
        }
        poolExecutor.shutdown();
    }

}

简单案列:
image

5.参考

链接!!!

posted @ 2022-03-26 15:56  土木转行的Genius  阅读(72)  评论(0)    收藏  举报