您的位置:首页 > 编程语言 > Java开发

Java 线程池理解汇总

2017-12-19 17:02 141 查看

Java中用到线程的情况一般都是使用线程池,省去了创建销毁线程的资源浪费,也可以统一管理线程,关于线程池还是有必要深入了解一下的

线程池了解还是从三个方面入手

一、线程池的优缺点

优点:减少系统创建销毁线程对资源的浪费,对线程统一管理,可以有效的控制最大并发数,提高系统资源的使用率,同时避免过多的资源竞争,避免阻塞。

缺点:使用不当有可能造成过多的创建线程造成死机。

二、线程池的使用以及理解

Java中Executors提供了四种常用的线程池,也可以通过ThreadPoolExecutor创建自定义线程池。

关于Executors提供的四种常用线程池如下:

1.newCachedThreadPool

创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无线程可用,则创建心线程,可以看到最大线程数是int最大值,适用于短期异步任务,但是并发量不大,或者负载较轻的服务器。

测试demo



通过修改是否休眠可以验证线程池是动态创建修改的

2.newFixedThreadPool

创建一个定长的线程池,可控制最大并发数,超出的线程任务会在队列中等待,适用于需要限制最大并发数的场景

测试demo



发现不管任务多少,只有两个线程在处理任务。

3.newSingleThreadExecutor

创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定书序执行,如果出现异常,会再新建一个线程继续执行,使用与有顺序要求的场景。



运行可以发现,如果出现异常,会创建新的线程继续执行接下来的任务

4.newScheduledThreadPool

创建一个定长的线程池,支持定时及周期性任务执行

测试例子:



延迟1秒执行,每两秒执行一次

除了ScheduledThreadPool其他的都是返回的ExecutorService,ExecutorService参数最全面的构造方法如下:



可以通过ExecutorService自定义自己需要的线程池,所以更需要了解各个参数的意义。

corePoolSize(核心线程数)

当提交一个新任务到线程池,线程池会创建一个新的线程来执行任务,无论其他基本线程是否是空闲状态,这种情况会持续到线程数量达到核心线程数,如果有空闲线程,则不会再新建新的线程

maximumPoolSize(最大线程数)

线程池允许创建的最大线程数,如果缓存队列满了,并且线程数小于最大线程数,这个线程池就会创建新的线程,一直达到最大线程数,如果还有任务,则根据一定策略处理。

keepAliveTime(线程活跃时间)

线程空闲之后存活的时间

unit(时间单位,针对keepAliveTime)

线程活跃时间的单位

workQueue(任务缓存队列)

当任务线程数达到核心线程数时,如果有多余的任务就放在缓存队列中,当缓存队列满了再创建小于最大线程数的线程,关于缓存队列可以选择以下几种:

1.ArrayBlockingQueue:基于数组的阻塞队列,安装FIFO(先进先出)的原则进行排序

2.LinkBlockingQueue:基于链表的阻塞队列,按照先进先出的原则进行排序,吞吐量高于ArrayBlockingQueue

3.SynchronousQueue:一个不存储元素的阻塞队列,每一个插入操作必须等到另外一个线程调用移除操作,否则插入操作一直处于阻塞状态

4.PriorityBlockingQueue:一个具有优先级的无限阻塞队列

threadFactory(线程工程)

用于设置创建新的线程的工程,一般用不到

handler(饱和策略)

这本身是java的一个接口,当队列和线程池都满了,需要一种策略处理新的任务,Java中提供了四种内置的实现类:

1.AbortPolicy 直接抛出异常

2.CallerRunPolicy 只用调用者所在的线程来运行任务

3.DiscardOldestPolicy 丢弃队列里面最近的一个任务,并执行当前的任务

4.DiscardPolicy 不处理,直接丢弃

5.实现RejectedExecutionHandler接口,自定义策略

三、线程池相关面试题(持续更新)

1. 如何避免死锁?

Java多线程中的死锁

死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足以下四个条件:

互斥条件:一个资源每次只能被一个进程使用。

请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。

循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。

2.Java线程池中submit() 和 execute()方法有什么区别?

两个方法都可以向线程池提交任务,execute()方法的返回类型是void,它定义在Executor接口中, 而submit()方法可以返回持有计算结果的Future对象,它定义在ExecutorService接口中,它扩展了Executor接口,其它线程池类像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有这些方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 线程池