线程池的作用
1、减少线程创建与切换的开销
- 在没有使用线程池的时候,来了一个任务,就创建一个线程,我们知道系统创建和销毁工作线程的开销很大,而且频繁的创建线程也就意味着需要进行频繁的线程切换,这都是一笔很大的开销。
2、控制线程的数量
- 使用线程池我们可以有效地控制线程的数量,当系统中存在大量并发线程时,会导致系统性能剧烈下降。
3、循环利用有限的线程
- 线程池中会预先创建一些空闲的线程,他们不断的从工作队列中取出任务,然后执行,执行完之后会继续执行工作队列中的下一个任务,减少了创建和销毁线程的次数,每个线程都可以一直被重用,节省创建和销毁的开销。
线程池的使用
常用Java线程池本质上都是由ThreadPoolExecutor或者ForkJoinPool生成的,只是其根据构造函数传入不同的实参来实例化相应线程池而已。
(1)Executors是一个线程池工厂类,该工厂类包含如下集合静态工厂方法来创建线程池:
- newFixedThreadPool():创建一个任务固定大小、任务队列无界限、可重用的、具有固定线程数的线程池(oom)
- newSingleThreadExecutor():创建只有一个线程的线程池
- newCachedThreadPool():创建一个具有缓存功能的线程池
- newScheduledThreadPool():创建具有指定线程数的线程池,它可以在指定延迟后执行任务线程
- newWorkStealingPool():创建持有足够线程的线程池来支持给定的并行级别的线程池
(2)ExecutorService接口 Java线程池也采用了面向接口编程的思想,可以看到ThreadPoolExecutor和ForkJoinPool所有都是ExecutorService接口的实现类,在ExecutorService接口中定义了一些常用的方法,然后再各种线程池中都可以使用ExecutorService接口中定义的方法,常用的方法有如下几个:
向线程池提交线程
- Future<?> submit():将一个Runnable对象交给指定的线程池,线程池将在有空闲线程时执行Runnable对象代表的任务,该方法既能接收Runnable对象也能接收Callable对象,这就意味着sumbit()方法可以有返回值。
- void execute(Runnable command):只能接收Runnable对象,意味着该方法没有返回值。
关闭线程池
- void shutdown():阻止新来的任务提交,对已经提交了的任务不会产生任何影响。(等待所有的线程执行完毕才关闭)
- List<Runnable> shutdownNow(): 阻止新来的任务提交,同时会中断当前正在运行的线程,另外它还将workQueue中的任务给移除,并将这些任务添加到列表中进行返回。(立马关闭)
检查线程池状态
- boolean isShutdown():调用shutdown()或shutdownNow()方法后返回为true
- boolean isTerminated():当调用shutdown()方法后,并且所有提交的任务完成后返回为true;当调用shutdownNow()方法后,成功停止后返回为true。
常见线程池使用示例
(1)newFixedThreadPool (线程池中的线程数目是固定的,不管来了多少的任务)
package 线程池;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* @author Heian
* @time 19/03/17 21:11
*/
public class ExecutorSer {
public static void sleepOneSecond(){
try {
TimeUnit.SECONDS.sleep (1);
} catch (InterruptedException e) {
e.printStackTrace ();
}
}
public static void sleepFiveSecond(){
try {
TimeUnit.SECONDS.sleep (5);
} catch (InterruptedException e) {
e.printStackTrace ();
}
}
public static void main(String[] args) {
//(1)newFixedThreadPool(线程池中的线程数目是固定的,不管来了多少的任务)
ExecutorService executorService = Executors.newFixedThreadPool (5);
System.out.println ("FixedThreadPool" + executorService);
//[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
for (int i=0;i<6;i++) //定义6个任务
executorService.execute (() -> {
ExecutorSer.sleepOneSecond ();
System.out.println (Thread.currentThread ().getName ());
});
System.out.println ("线程正在执行任务的状态:" +executorService);
//[Running, pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0] 如果是三个任务,则pool size=3 说明线程池是懒加载方式创建线程
executorService.shutdown ();//此方法会让所有线程执行完毕后在关闭,shutdownNow:立马关闭
System.out.println ("是否执行shutdown方法:"+ executorService.isShutdown () + "执行shutdown方法后状态:"+ executorService) ;
//true ,[Shutting down, pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0]
System.out.println ("是否所有线程已经执行完毕:" + executorService.isTerminated ());
ExecutorSer.sleepFiveSecond ();
System.out.println ("5s后,是否执行shutdown方法:"+ executorService.isShutdown () + "执行shutdown方法后状态:"+ executorService) ;
//true 执行shutdown方法后状态:java.util.concurrent.ThreadPoolExecutor@28864e92[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 6]
System.out.println ("5s后,是否所有线程已经执行完毕:" + executorService.isTerminated ());//true
}
}
(2)newSingleThreadExecutor(从头到尾整个线程池都只有一个线程在工作)
ExecutorService executorService1 = Executors.newSingleThreadExecutor ();
for (int i=0;i<5;i++)
executorService1.execute (() -> {
System.out.println (Thread.currentThread ().getName ());
});
//可以看到至始至终就只有一个线程在执行任务
/* pool-2-thread-1
pool-2-thread-1
pool-2-thread-1
pool-2-thread-1
pool-2-thread-1*/
(3)newCachedThreadPool
ExecutorService executorService2 = Executors.newCachedThreadPool ();
System.out.println (executorService2);
for (int i=0;i<12;i++)
executorService2.execute (() -> {
ExecutorSer.sleepOneSecond ();
System.out.println (executorService2);
});
System.out.println ("CacheThreadPool线程提交后,线程状态为" + executorService2);
/* java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
CacheThreadPool线程提交后,线程状态为java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 12, queued tasks = 0, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 12, queued tasks = 0, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 12, queued tasks = 0, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 12, queued tasks = 0, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 12, queued tasks = 0, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 8, queued tasks = 0, completed tasks = 4]
java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 7, queued tasks = 0, completed tasks = 5]
java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 6, queued tasks = 0, completed tasks = 6]
java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 5, queued tasks = 0, completed tasks = 7]
java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 5, queued tasks = 0, completed tasks = 7]
java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 3, queued tasks = 0, completed tasks = 9]
java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 2, queued tasks = 0, completed tasks = 10]
java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 1, queued tasks = 0, completed tasks = 11]*/
(4)newScheduledThreadPool (可以在指定延迟后或周期性地执行线程任务的线程池)
//建立四个线程 每个500毫秒去打印当前线程的名称
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool (4);
scheduledExecutorService.scheduleAtFixedRate (() -> {
System.out.println (Thread.currentThread ().getName ());
},0,500,TimeUnit.MILLISECONDS);
callable接口的使用
Callable接口实际上是属于Executor框架中的功能类,Callable接口与Runnable接口的功能类似,但提供了比Runnable更加强大的功能。
- Callable可以在任务结束的时候提供一个返回值,Runnable无法提供这个功能
- Callable的call方法分可以抛出异常,而Runnable的run方法不能抛出异常。
package 线程池.ICallabl;
import java.util.concurrent.*;
/**
* @author Heian
* @time 19/03/23 22:27
* 用途:模拟异步发送接口
*/
public class Icallable {
//Callable泛型为其异步返回的结果类型 Callable函数式接口
static class sendEmail implements Callable<String> {
private long sleepTime;
public sendEmail(long sleepTime) {
this.sleepTime = sleepTime;
}
@Override
public String call() throws Exception {
Thread.sleep (sleepTime);
System.out.println ("发送emails完毕:"+ Thread.currentThread ().getName ());
return Thread.currentThread ().getName ();
}
}
static class sendPhoneMsg implements Callable<String> {
private long sleepTime;
public sendPhoneMsg(long sleepTime) {
this.sleepTime = sleepTime;
}
@Override
public String call() throws Exception {
Thread.sleep (sleepTime);
System.out.println ("发送短信完毕:"+ Thread.currentThread ().getName ());
return Thread.currentThread ().getName ();
}
}
public static void main(String[] args) throws Exception{
long start = System.currentTimeMillis ();
sendEmail sendEmail = new sendEmail (5000);
sendPhoneMsg sendPhoneMsg = new sendPhoneMsg (8000);
FutureTask<String> sendEmailTask = new FutureTask<> (sendEmail);
FutureTask<String> sendPhonneMsgTask = new FutureTask<> (sendPhoneMsg);
ExecutorService executorService = Executors.newFixedThreadPool (3);//线程池中的线程数目是固定的,来了多少任务,启动多少线程
executorService.execute (sendEmailTask);
executorService.execute (sendPhonneMsgTask);
while(true){
if(!sendEmailTask.isDone ()){
TimeUnit.MILLISECONDS.sleep (500);
System.out.println ("enlias发送中,请稍后" + Thread.currentThread ().getName ());
}
if(!sendPhonneMsgTask.isDone ()){
TimeUnit.MILLISECONDS.sleep (500);
System.out.println ("短信发送中,请稍后"+ Thread.currentThread ().getName ());
}
if (sendEmailTask.isDone () && sendPhonneMsgTask.isDone ()){
System.out.println ("两个线程执行完毕");
executorService.shutdown ();//所有线程执行完毕后再关闭
return;
}
//执行完成
long end = System.currentTimeMillis ();
System.out.println ("耗时" +(end-start) + "毫秒");
}
/* while (true){// email:2 短信:5
if (sendEmailTask.isDone ()){//isDone方法表示任务是否已经完成,若任务完成,则返回true;
System.out.println ("email执行完毕" + sendEmailTask.get ());//方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
}
if (sendEmailTask.isDone () && sendPhonneMsgTask.isDone ()){
System.out.println ("两个线程执行完毕");
executorService.shutdown ();//所有线程执行完毕后再关闭
return;
}
}*/
}
}
Callable 拓展
package 线程池.ICallabl;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* 模拟业务场景:处理耗时任务,它会以最长的业务时间返回,不是响应式
*/
public class InvokeAllTest {
//任务一
public String do3Second() {
try {
System.out.println ("正在执行3秒的方法");
TimeUnit.SECONDS.sleep (3);
} catch (Exception e) {
e.printStackTrace ();
}
return Thread.currentThread ().getName () + "##3";
}
//任务二
public String do5Second() {
try {
System.out.println ("正在执行5秒的方法");
TimeUnit.SECONDS.sleep (5);
} catch (Exception e) {
e.printStackTrace ();
}
return Thread.currentThread ().getName () + "##5";
}
public static void main(String[] args) throws Exception{
long start = System.currentTimeMillis ();
InvokeAllTest demo = new InvokeAllTest ();
ExecutorService executorService = Executors.newFixedThreadPool (20);
List<Callable<String>> callList = new ArrayList<> ();
for (int value = 0; value < 5; value++) {
callList.add (() -> demo.do3Second ());
callList.add (() -> demo.do5Second ());
}
//把所有的任务放入到线程池里
List<Future<String>> futures = executorService.invokeAll (callList);
futures.forEach (strFture ->{
while (true){
//只有当所有任务执行了,返回结果集
if (strFture.isDone ()){
String s = null;
try {
s = strFture.get ();
System.out.println (s + "耗时:" + (System.currentTimeMillis () - start));
break;
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace ();
}
}
}
});
System.out.println ("阻塞此处 执行完毕");
executorService.shutdown ();
}
}
正在执行3秒的方法
正在执行5秒的方法
正在执行3秒的方法
正在执行5秒的方法
正在执行3秒的方法
正在执行5秒的方法
正在执行3秒的方法
正在执行5秒的方法
正在执行5秒的方法
正在执行3秒的方法
pool-1-thread-1##3耗时:5078
pool-1-thread-2##5耗时:5078
pool-1-thread-3##3耗时:5078
pool-1-thread-4##5耗时:5078
pool-1-thread-5##3耗时:5078
pool-1-thread-6##5耗时:5078
pool-1-thread-7##3耗时:5078
pool-1-thread-8##5耗时:5078
pool-1-thread-9##3耗时:5078
pool-1-thread-10##5耗时:5078
阻塞此处 执行完毕
将任务加入到集合并发的执行,因为必须等到每一个线程执行成功后方能退出循环,所以打印时间都是以最长的时间为准的,并不能做到响应式编程,优化后代码如下:
package 线程池.ICallabl.异步非阻塞;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
/**
* 模拟业务场景:处理耗时任务,处理完一个任务返回一个任务结果,响应式
*/
public class ComletableTest {
//任务一
public String do3Second() {
try {
System.out.println ("正在执行3秒的方法");
TimeUnit.SECONDS.sleep (3);
} catch (Exception e) {
e.printStackTrace ();
}
return Thread.currentThread ().getName () + "##3";
}
//任务二
public String do5Second() {
try {
System.out.println ("正在执行5秒的方法");
TimeUnit.SECONDS.sleep (5);
} catch (Exception e) {
e.printStackTrace ();
}
return Thread.currentThread ().getName () + "##5";
}
public static void main(String[] args) {
long start = System.currentTimeMillis ();
ComletableTest demo = new ComletableTest ();
AtomicInteger num = new AtomicInteger ();
ExecutorService executorService = Executors.newFixedThreadPool (20);
IntStream.range (0,5).forEach (value -> {
CompletableFuture.supplyAsync (() -> {
return demo.do3Second ();
},executorService).whenComplete ((resultStr, throwable) -> {
num.addAndGet (1);
System.out.println (resultStr + "耗时:" + (System.currentTimeMillis () - start));
});
CompletableFuture.supplyAsync (() -> {
return demo.do5Second ();
},executorService).whenComplete ((resultStr, throwable) -> {
num.addAndGet (1);
System.out.println (resultStr + "耗时:" + (System.currentTimeMillis () - start));
});
});
System.out.println ("非阻塞 执行完毕");
while (true){
if (num.get () == 10){
System.out.println ("任务执行完毕!");
executorService.shutdown ();
break;
}
}
}
}
正在执行3秒的方法
正在执行5秒的方法
正在执行5秒的方法
正在执行3秒的方法
非阻塞 执行完毕
正在执行3秒的方法
正在执行5秒的方法
正在执行3秒的方法
正在执行5秒的方法
正在执行3秒的方法
正在执行5秒的方法
pool-1-thread-1##3耗时:3075
pool-1-thread-5##3耗时:3078
pool-1-thread-3##3耗时:3078
pool-1-thread-7##3耗时:3079
pool-1-thread-9##3耗时:3079
pool-1-thread-4##5耗时:5079
pool-1-thread-6##5耗时:5079
pool-1-thread-2##5耗时:5079
pool-1-thread-8##5耗时:5080
pool-1-thread-10##5耗时:5083
任务执行完毕!
需要注意一点的就是: supplyAsync、whenComplete使用的都是deamon线程,主线程退出,会导致任务异常关闭
package 线程池.ICallabl.异步非阻塞;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
/**
*whenComplete 完成时 触发的事件 supplyAsync、whenComplete使用的都是deamon线程,主线程退出后,进程退出,导致结果没有打印
*/
public class ComletableDemo {
//任务一
public String do3Second() {
try {
System.out.println ("正在执行3秒的方法");
TimeUnit.SECONDS.sleep (3);
} catch (Exception e) {
e.printStackTrace ();
}
return Thread.currentThread ().getName () + "##3";
}
//任务二
public String do5Second() {
try {
System.out.println ("正在执行5秒的方法");
TimeUnit.SECONDS.sleep (5);
} catch (Exception e) {
e.printStackTrace ();
}
return Thread.currentThread ().getName () + "##5";
}
public static void main(String[] args) throws Exception{
long start = System.currentTimeMillis ();
ComletableDemo demo = new ComletableDemo ();
IntStream.range (0,5).forEach (value -> {
CompletableFuture.supplyAsync (() -> {
return demo.do3Second ();
}).whenComplete ((resultStr, throwable) -> {
System.out.println (resultStr + "耗时:" + (System.currentTimeMillis () - start));
});
CompletableFuture.supplyAsync (() -> {
return demo.do5Second ();
}).whenComplete ((resultStr, throwable) -> {
System.out.println (resultStr + "耗时:" + (System.currentTimeMillis () - start));
});
});
System.out.println ("我没有被阻塞住");
Runtime.getRuntime ().addShutdownHook (new Thread (() -> {
System.out.println ("任务执行完成,JVM退出程序");
}));
// Thread.sleep (1000000L);
}
//supplyAsync 默认使用的是守护线程,所以当执行到main线程后,已经没有非守护线程了,此时任务还没执行完成,所以要指定线程池
}
正在执行3秒的方法
正在执行5秒的方法
我没有被阻塞住
正在执行3秒的方法
任务执行完成,JVM退出程序
自定义单例线程池和自定义线程名称
在任务不多的情况下,其实一个项目是可以公用一个线程池,那么我们就联想到了单例模式,那我们可以用7种单利模式中的holder模式去涉及,而且为了便于区分每个线程的名称(一般线程池线程名称为pool-1-thread-2 其组成为:线程组名+线程名),而且一般要实现线程自定义命名必须要实现ThreadFactory接口,具体实现方法,可以参见Executors这个类,这个类有个内部类实现了ThreadFactory接口,源码如下:
/**
* The default thread factory
*/
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;//线程名后缀
MyThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-";
//如果这个内部类是外部类,那么每调用一次poolNumber就会+1,目前内部类实际上就固定不变了1
}
//线程工厂 制造线程
public Thread newThread(Runnable r) {
//线程构造方法
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
//将守护线程设置为非守护线程
if (t.isDaemon())
t.setDaemon(false);
//统一将线程优先级设置为5 默认是5 Thread.NORM_PRIORITY
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
package 线程池.自定义线程池线程名称;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author heian
* @create 2020-01-08-1:55 下午
* @description 单例自定义线程池
*/
public final class SingleThreadPool {
private ExecutorService executors = new ThreadPoolExecutor
(5,10,3, TimeUnit.SECONDS,new LinkedBlockingQueue<>(10),new SingleThreadPool.MyThreadFactory());
private SingleThreadPool(){
}
//静态内部类
private static class Holder{
private static SingleThreadPool singleThreadPool = new SingleThreadPool();
}
//静态内部类
private static class MyThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;//线程名后缀
MyThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
namePrefix = "myPool-" + poolNumber.getAndIncrement() + "-myThread-";
//如果这个内部类是外部类,那么每调用一次poolNumber就会+1,目前内部类实际上就固定不变了1
}
//线程工厂 制造线程
public Thread newThread(Runnable r) {
//线程构造方法
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
//将守护线程设置为非守护线程
if (t.isDaemon())
t.setDaemon(false);
//统一将线程优先级设置为5 默认是5 Thread.NORM_PRIORITY
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
//返回所需单例类
public static SingleThreadPool getInstance(){
return Holder.singleThreadPool;
}
//返回单例类所需变量
public ExecutorService getExecutors() {
return executors;
}
}
通过测试类测试
package 线程池.自定义线程池线程名称;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
/**
* @author heian
* @create 2020-01-08-2:18 下午
* @description 测试类
*/
public class TestSingle {
public static void task() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
ExecutorService executors = SingleThreadPool.getInstance().getExecutors();
for (int i = 0; i <10 ; i++) {
executors.submit(() -> {
try {
task();
System.out.println(executors.toString());
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
}
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/bin/java "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=55035:/Applications/IntelliJ IDEA.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/tools.jar:/Users/humingming/Downloads/firstPro/out/production/firstPro 线程池.自定义线程池线程名称.TestSingle
myPool-1-myThread-3
myPool-1-myThread-1
myPool-1-myThread-5
myPool-1-myThread-2
myPool-1-myThread-4
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 5, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 5, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 5, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 5, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 5, completed tasks = 0]
myPool-1-myThread-3
myPool-1-myThread-5
myPool-1-myThread-2
myPool-1-myThread-1
myPool-1-myThread-4
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 5]
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 5]
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 5]
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 5]
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 5]
可以看见 线程池名字改了,如果是多个线程池不公用则需要将实现MyThreadFactory类抽成一个单独的类,并且可以发现当任务为10线程只启动了5个,另外5个任务会进入队列。所以又有以下规则:
- 池中的线程 > corePoolSize 的线程,多出的线程在空闲时间keepAliveTime 时将会终止
- 运行的线程 < corePoolSize 的线程,则线程池继续添加新的线程,而不进行排队
- 运行的线程 >= corePoolSize 的线程,则线程池添加到队列,而不是增加线程
- maxPoolSize > 运行的线程 >corePoolSize,当且仅当线程池队列满,才会创建新的线程
- 池中的线程>maxPoolSize ,这种情况下会采取拒绝策略 (抛出RejectedExecutionException)
核心线程数10,最大线程数30,keepAliveTime是3秒
随着任务数量不断上升,线程池会不断的创建线程,直到到达核心线程数10,就不创建线程了,
这时多余的任务通过加入阻塞队列来运行,
当超出阻塞队列长度+核心线程数时,
这时不得不扩大线程个数来满足当前任务的运行,这时就需要创建新的线程了(最大线程数起作用),上限是最大线程数30
那么超出核心线程数10并小于最大线程数30的可能新创建的这20个线程相当于是“借”的,如果这20个线程空闲时间超过keepAliveTime,就会被退出