一、线程池的创建
JDK中提供了4个可重载的构造方法来创建一个线程池,参数少的构造方法将使用默认的参数调用参数多的构造方法。
构造方法:
public ThreadPoolExecutor( int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors. defaultThreadFactory(), defaultHandler);
}
参数说明:
corePoolSize(核心线程数):线程池中保持活动状态的最小线程数,即使是空闲状态也不会被回收。
maximumPoolSize(最大线程数):线程池中允许存在的最大线程数,包括核心线程数和非核心线程数。
keepAliveTime(线程空闲时间):当线程池中的线程数超过核心线程数时,空闲线程等待新任务的最长时间,超过这个时间将被回收销毁。
TimeUnit(时间单位):设置keepAliveTime的时间单位,可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。
workQueue(任务队列):用于存放等待执行的任务的阻塞队列,可以选择不同类型的队列,如:
ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。
SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
PriorityBlockingQueue:一个具有优先级的无限阻塞队列。
threadFactory(线程工厂):用于创建线程的工厂类,可以自定义线程的名称、优先级等属性。
rejectedExecutionHandler(任务拒绝策略):当线程池无法接收新任务时,执行的策略,如抛出异常、丢弃任务或者调用主线程来执行任务。
核心线程、最大线程数、线程空闲时间之间的关系:
当有新任务提交到线程池时,首先线程池会尝试使用核心线程来处理任务。
当核心线程都在执行任务且工作队列已满时,线程池会创建新的非核心线程来处理任务,直到达到最大线程数。
当非核心线程完成任务后,如果在线程空闲时间内没有新任务提交,这些线程将被销毁,以避免线程过多占用系统资源。
二、Executors提供了创建ThreadPoolExecutor的常用方法,主要有:
参考博客:https://blog.csdn.net/u014644594/article/details/103294628
1、 Executors.newFixedThreadPool(int nThreads);
说明:创建固定大小(nThreads, 大小不能超过int的最大值)的线程池
// 线程数量 int nThreads = 20;
// 创建executor 服务
ExecutorService executor = Executors.newFixedThreadPool(nThreads) ;
重载后的版本,需要传入实现了ThreadFactory接口的对象。
ExecutorService executor = Executors. newFixedThreadPool(nThreads, threadFactory);
说明:创建固定大小(nThreads, 大小不能超过int的最大值) 的线程池,缓冲任务的队列为LinkedBlockingQueue,大小为整型的最大数,当使用此线程池时,在同执行的任务数量超过传入的线程池大小值后,将会放入LinkedBlockingQueue,在LinkedBlockingQueue中的任务需要等待线程空闲后再执行,如果放入LinkedBlockingQueue中的任务超过整型的最大数 时,抛出RejectedExecutionException。
2、Executors.newSingleThreadExecutor():创建大小为1的固定线程池。
ExecutorService executor = Executors.newSingleThreadExecutor();
重载后的版本,需要多传入实现了ThreadFactory接口的对象。
ExecutorService executor = Executors. newSingleThreadScheduledExecutor(ThreadFactory threadFactory)
说明:创建大小为1的固定线程池,执行任务的线程只有一个,其它的(任务)task都放在LinkedBlockingQueue中排队等待执行。
3、Executors.newCachedThreadPool();创建corePoolSize为0,最大线程数为整型的最大数,线程 keepAliveTime为1分钟,缓存任务的队列为SynchronousQueue的线程池。
ExecutorService executor = Executors.newCachedThreadPool();
当然也可以以下面的方式创建,重载后的版本,需要多传入实现了ThreadFactory接口的对象。
ExecutorService executor = Executors.newCachedThreadPool(ThreadFactory threadFactory) ;
说明:使用时,放入线程池的task任务会复用线程或启动新线程来执行,注意事项:启动的线程数如果超过整型最大值后会抛出RejectedExecutionException异常,启动后的线程存活时间为一分钟。
4、Executors.newScheduledThreadPool(int corePoolSize):创建corePoolSize大小的线程池。
// 线程数量 int corePoolSize= 20;
// 创建executor 服务
ExecutorService executor = Executors.newScheduledThreadPool(corePoolSize) ;
重载后的版本,需要多传入实现了ThreadFactory接口的对象。
ExecutorService executor = Executors.newScheduledThreadPool(corePoolSize, threadFactory) ;
说明:线程keepAliveTime为0,缓存任务的队列为DelayedWorkQueue,注意不要超过整型的最大值。
备注:
FixedThreadPool 模式会使用一个优先固定数目的线程来处理若干数目的任务。规定数目的线程处理所有任务,一旦有线程处理完了任务就会被用来处理新的任务(如果有的话)。这种模式与上面的 CachedThreadPool是不同的。
CachedThreadPool 模式下处理一定数量的任务的线程数目是不确定的。而FixedThreadPool模式下最多的线程数目是一定的。
SingleThreadExecutor 模式只会创建一个线程。它和FixedThreadPool比较类似,不过线程数是一个。 如果多个任务被提交给SingleThreadExecutor的话 ,那么这些任务会被保存在一个队列中,并且会按照任务提交的顺序,一个先执行完成再执行另外一个线程。 SingleThreadExecutor模式可以保证只有一个任务会被执行。 这种特点可以被用来处理共享资源的问题而不需要考虑同步的问题。
即在Java中,常见的线程池类型包括以下几种::
线程的状态:
在线程的生命周期中,线程可以处于不同的状态。Java中的线程共有6种状态:
yield、sleep、wait和join是Java中用于线程控制的方法,它们之间有以下区别:
yield()方法:
sleep()方法:
wait()方法:
join()方法:
总结:
yield()方法是让出CPU执行时间给同优先级的其他线程;
sleep()方法是使当前线程暂停执行一段时间;
wait()方法是使当前线程进入阻塞状态并释放锁资源,需要通过其他线程来唤醒;
join()方法是让当前线程等待被调用线程执行完毕。
线程池的使用,可参考博客:https://blog.csdn.net/m0_53714343/article/details/131438982