Java 中的 Executors 类提供了创建和管理线程池的工厂方法。主要有以下三种常用的静态工厂方法:
newFixedThreadPool(int nThreads):固定的线程池大小
创建一个固定大小的线程池,其中包含指定数量的线程。如果所有线程都处于活动状态,并且任务队列已满,那么新任务将在任务队列中等待,直到有空闲的线程可用。
newCachedThreadPool():遇强则强,遇弱则弱
创建一个可缓存的线程池,如果线程池的当前规模超过处理需求时,它会回收空闲线程;当需求增加时,则可以添加新的线程,线程池规模不存在限制。
这些工厂方法都返回实现了 ExecutorService 接口的 ThreadPoolExecutor 对象,这是 Java 线程池的一个具体实现,提供了对线程池的操作和控制。通过使用这些工厂方法创建线程池,可以方便快捷地满足不同场景下的线程管理需求。
由于使用Executors不安全,那么我们需要手动创建一个线程池
线程池是一种用于管理和重用线程的机制,它通过预先创建一组线程,并将任务提交给这些线程来执行。线程池可以有效地控制并发线程的数量,避免了频繁创建和销毁线程的开销,提高了系统的性能和资源利用率。
线程池通常由以下组件构成:
线程池的主要优点包括:
使用线程池时,需要根据具体的业务需求和系统资源情况合理配置线程池的大小、任务队列的容量以及其他相关参数,避免因线程池过小或过大导致的性能问题。
newSingleThreadExecutor的源码
newFixedThreadPool的源码
newCachedThreadPool的源码
其中有个参数长度是Integer,MAX_VALUE,长度过大,可能会堆积大量的请求,对应了上面我们说的不能用Executors,而要用ThreadPoolExecutors
我们发现,上面三者的源码中都有ThreadPoolExecutor
说明调用线程的本质调用的是ThreadPoolExecutor
下面我们来分析一下ThreadPoolExecutor
下面我们来想象一个场景,来更好的理解线程池
比如我们去银行办理业务
银行有5个窗口,但是只打开了2个(代表核心线程池的大小为2),还有3个没有开(触发最大并发量的情况下才会打开这3个窗口),还有容量为3的候客区(阻塞队列)
然后有用户去办理业务了,假如来了3个用户,2个去窗口了,还有1个在候客区等待,此时,又来了3个用户,这时候客区的位置不够了(阻塞队列满了),就要打开那关闭的3个窗口(触发最大并发量了)
package org.Test6;
import java.util.concurrent.*;
public class Demo01 {
public static void main(String[] args) {
//自定义线程池
ExecutorService threadPool = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS, //超时等待时间
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
try {
for (int i = 1; i <= 10; i++) {
//使用线程池后,使用线程池来创建线程
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"ok");
});
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭线程池
threadPool.shutdown();
}
}
}
代码里面的超时等待时间是什么意思
我们对应上面去银行的场景,触发最大并发条件后,所有窗口都打开了,一段时间后,所有用户都离开了,过了设定的时间都没有业务,那么后面3个窗口就要关闭
package org.Test6;
import java.util.concurrent.*;
public class Demo01 {
public static void main(String[] args) {
//自定义线程池
ExecutorService threadPool = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS, //超时等待时间
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
try {
for (int i = 1; i <= 10; i++) {
//使用线程池后,使用线程池来创建线程
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"ok");
});
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭线程池
threadPool.shutdown();
}
}
}
package org.Test6;
import java.util.concurrent.*;
public class Demo01 {
public static void main(String[] args) {
//自定义线程池
ExecutorService threadPool = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS, //超时等待时间
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardPolicy()
);
try {
for (int i = 1; i <= 10; i++) {
//使用线程池后,使用线程池来创建线程
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"ok");
});
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭线程池
threadPool.shutdown();
}
}
}
丢掉任务,但是不会抛出异常
package org.Test6;
import java.util.concurrent.*;
public class Demo01 {
public static void main(String[] args) {
//自定义线程池
ExecutorService threadPool = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS, //超时等待时间
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardOldestPolicy()
);
try {
for (int i = 1; i <= 10; i++) {
//使用线程池后,使用线程池来创建线程
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"ok");
});
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭线程池
threadPool.shutdown();
}
}
}
在技术的道路上,我们不断探索、不断前行,不断面对挑战、不断突破自我。科技的发展改变着世界,而我们作为技术人员,也在这个过程中书写着自己的篇章。让我们携手并进,共同努力,开创美好的未来!愿我们在科技的征途上不断奋进,创造出更加美好、更加智能的明天!