new

线程池

2021-03-24  本文已影响0人  因你而在_caiyq

原创文章,转载请注明原文章地址,谢谢!

线程池最主要的工作在于控制运行线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。从而做到线程复用、控制最大并发数量、管理线程。

线程池优势
线程池中的继承实现关系
线程池的使用方式
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                    0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
            60L, TimeUnit.SECONDS,
            new SynchronousQueue<Runnable>());
}

以上三种创建线程的方式内部都是由ThreadPoolExecutor这个类完成的,该类的构造方法有5个参数,称为线程池的5大参数。线程池使用完毕之后需要关闭,应该配合try-finally代码块,将线程池关闭的代码放在finally代码块中。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public static ExecutorService newWorkStealingPool() {
    return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
                    ForkJoinPool.defaultForkJoinWorkerThreadFactory,
                    null, true);
}
线程池的参数
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
}

corePoolSize:线程池中常驻核心线程池。
maximumPoolSize:线程池中能够容纳同时执行最大线程数,该值必须大于等于1。
keepAliveTime:多余线程的最大存活时间。
unit:keepAliveTime的单位。
workQueue:任务队列,被提交但尚未被执行的任务。
threadFactory:生成线程池中工作线程的线程工厂,一般使用默认即可。
handler:拒绝策略,表示当任务队列满并且工作线程大于等于线程池的最大线程数时,对即将到来的线程的拒绝策略。

线程池的底层原理

1、在创建线程池后,等待提交过来的任务请求。
2、当调用execute()/submit()方法添加一个请求任务时,线程池会做出以下判断

3、当一个线程完成任务时,它会从队列中取下一个任务来执行。
4、当一个线程空闲时间超过给定的keepAliveTime时,线程会做出判断:如果当前运行线程大于corePoolSize,那么该线程将会被停止。即当线程池的所有任务都完成之后,它会收缩到corePoolSize的大小。


线程池的拒绝策略

当线程池的阻塞队列满了同时线程池中线程数量达到了maximumPoolSize时,线程池将会启动相应的拒绝策略来拒绝请求任务。

注意

public static void main(String[] args) {
    ExecutorService executor = new ThreadPoolExecutor(
            2,
            5,
            1L,
            TimeUnit.SECONDS,
            new LinkedBlockingDeque<>(3),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.CallerRunsPolicy());
    try {
        for (int i = 0; i < 10; i++) {
            executor.execute(() -> {
                System.out.println(Thread.currentThread().getName() + " 办理业务");
            });
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        executor.shutdown();
    }
}
线程池配置合理线程数量

线程池合理配置线程数量需要考虑业务具体是CPU密集型还是IO密集型。
1、CPU密集型:该任务需要大量运算,而没有阻塞,CPU一直在全速运行,CPU密集型只有在真正的多核CPU上才能进行加速。

2、IO密集型:任务需要大量的IO操作,即大量的阻塞。在单线程上进行IO密集型的任务会浪费大量的CPU运算能力在等待操作上。所以在IO密集型任务中使用多线程可以大大加速程序运行,即使在单核CPU上,这种加速主要就是利用了被浪费掉的阻塞时间。

博客内容仅供自已学习以及学习过程的记录,如有侵权,请联系我删除,谢谢!

上一篇下一篇

猜你喜欢

热点阅读