JUC之线程池

若有不对之处欢迎大家指出,这个也是在学习工作中的一些总结,侵删!
得之在俄顷,积之在平日。

1、 使用线程池的好处

加快响应速度。
合理利用CPU和内存。
统一管理资源。

2、线程池的使用场合

服务器接收到大量请求时,它可以减少线程的创建和销毁次数,提高服务器工作效率。
在开发中如果需要创建5个以上的线程,那么就可以使用线程池来管理。

3、 创建和停止线程池
一、 线程池的构造函数
在这里插入图片描述

	CorePoolSize:核心线程数,线程池在完成初始化后,默认情况下线程池并没有任何线程,线程池会等待有任务到来时,再创建新的线程去执行任务。
	maxPoolSize:线程池有可能会在核心线程数的基础上额外增加一些线程,但是这些新增加的线程数会有一个上限,这就是最大线程数maxPoolSize。
	keepAliveTime:如果线程池当前线程数多余corePoolSize,那么多余的线程的空闲时间超过keepAliveTime,它们就会被终止。
	ThreadFactory:线程工厂,用来创建线程,默认使用Executors.defaultThreadFactory()创建出来的线程都在同一个线程组,拥有同样的NORM_PRIORITY优先级(默认5)并且都不是守护线程。如果自己指定ThreadFactory,那么就可以改变线程名、线程组、优先级、是否为守护线程等。
	workQueue:工作队列,有三种常见的队列类型:
		直接交接:SynchronousQueue
		无界队列:LinkedBlockingQueue
		有界队列:ArrayBlockingQueue

在这里插入图片描述
二、添加线程的规则

如果线程数小于corePollSize,即使其他工作线程处于空闲状态,也会创建一个新的线程来运行新任务
如果线程数等于或大于corePoolSize但少于maxPoolSize,则将任务放入队列。
如果队列已满,并且线程数小于maxPoolSize,则会创建一个新线程来执行任务
如果队列已满,并且线程数大于或等于maxPoolSize,则拒绝任务
图解:

在这里插入图片描述
例:核心线程池大小为5,maxPoolSize为10 ,队列为100
线程中的请求最多会创建5个线程,然后将任务添加到队列中,直达队列已满,然后会创建新的线程执行任务,最多maxPoolSize,如果再来任务就执行拒绝策略。
三、 增减线程的特点

通过设置corePoolSize和maxPoolSize相同就可以创建固定大小的线程池。
线程池希望保持较少的线程数,并且只有在负载很大的时候才增加线程数。
通过设置maxPoolSize为很高的值,例如Integer.MAX_VALUE,可以允许线程池容纳任意数量的并发任务。
只有在队列填满时才创建多余corePoolSize的线程,所以如果使用的是无界队列(例如:LinkedBlockingQueue)那么线程数就不会超过corePoolSize。

四、 线程池的使用
1)newFixedThreadPool

public class TestThread {
    class Run implements Runnable{
        @Override
        public void run() {
            System.out.println("当前线程名称:"+Thread.currentThread().getName());
        }
    }
    //创建线程池
    ExecutorService executorService = Executors.newFixedThreadPool(4);
    @Test
    public void Test(){
        for (int i = 0; i <100000000 ; i++) {//i的数值要大
            executorService.submit(new Run());
        }
        executorService.shutdown();
    }
}

源码图:
在这里插入图片描述
从源码可以看出,这种线程池采用的是无界队列,任何时候最多有NThreads个工作线程是活动着的,这意味着如果任务数量超过了活动队列数目,将在工作队列中等待空闲线程出现,如果有工作线程退出,将会有新的工作线程被创建,以补足指定数目的NThreads;如果请求数越来越多且无法及时处理完时,会造成占用大量内存,可能会导致OOM
2) newSingleThreadExecutor

//创建线程池
ExecutorService executorService = Executors.newSingleThreadExecutor();

源码:
在这里插入图片描述
从源码可以看出它和newFixedThreadPool原理基本一样,只是线程数直接设置成看1 ,所以它保证了所有任务都被顺序执行,也会导致请求数越来越多且无法及时处理完时,会造成占用大量内存,可能会导致OOM。
3) newCachedThreadPool

//创建可缓存线程池
ExecutorService executorService = Executors.newCachedThreadPool();

源码:
在这里插入图片描述
它是用来处理大量短时间工作任务的线程池,具有几个鲜明的特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程,如果线程空闲时间超过60秒,则被终止并移除缓存长时间闲置时这种线程不会消耗资源,其内部使用的是直接交接工作队列(SynchronousQueue);maxPoolSize值为Integer.MAX_VALUE,这可能会导致创建非常多的线程而出现OOM
4)newScheduledThreadPool

class Run implements Runnable{
    @Override
    public void run() {
        System.out.println("当前线程名称:"+Thread.currentThread().getName());
    }
}
//创建线程池
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(4);
@Test
public void Test(){
    for (int i = 0; i <100 ; i++) {
        //常规用法
        //scheduledExecutorService.submit(new Run());
        //定时调度 
        scheduledExecutorService.scheduleAtFixedRate(new Run(),0,100,TimeUnit.SECONDS);
    }
}

源码:
在这里插入图片描述
返回值是:ScheduledExecutorService,可以支持定时或周期性任务调度。
5) newSingleThreadScheduledExecutor

//创建线程池
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

源码:
在这里插入图片描述
与newScheduledThreadPool类似,同样支持定时调度,区别在于newScheduledThreadPool是多个工作线程,newSingleThreadScheduledExecutor是单一工作线程。
6) newWorkStealingPool
五、停止线程池

shutdown():不接受新任务,但会把当前任务和队列中的任务执行完
shutdownNow():立刻关闭线程池,但会执行完当前任务,不会执行队列中的任务,并返回队列中的任务:`List<Runnable> runnables = scheduledExecutorService.shutdownNow();`

六、拒绝策略
1)拒绝时机

当Executor关闭时,提交新任务会被拒绝
当Executor对最大线程和工作队列容量使用有限边界并且已经饱和时

2)4种拒绝策略

AbortPolicy:当任务添加到线程池中被拒绝时,它将抛出 RejectedExecutionException异常
DiscardPolicy:当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝的任务。
DiscardOldestPolicy:丢弃阻塞队列 workQueue 中最老的一个任务,并将新任务加入 
CallerRunsPolicy:该任务被线程池拒绝,由调用 execute方法的线程执行该任务。

七、线程池的状态

Running:接收新任务并处理排队中的任务。
Shutdown:不接收新任务但会处理排队中的任务。
Stop:不接收新任务,不处理排队中的任务并中断正在执行的任务。
Tidying:所有任务都销毁了,workCount为0,线程池的状态转换为Tidying状态时,会执行钩子方法terminated()。
Terminated: terminated()方法结束后,线程池就会变成这个。

八、使用线程池注意点

避免任务堆积
避免线程过度增加
排查线程泄漏
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值