主要有分两种方式:
一:通过Executors创建线程池
二:通过ThreadPoolExecutor创建线程池
一:通过Executors创建线程池
1.通过Executors.newFixedThreadPool创建
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Description:创建一个固定大小的线程池
* Date: 2022/10/29 15:47
**/
public class CreatThreadPoolDemo1 {
public static void main(String[] args) {
// 创建3个数量级的线程池
ExecutorService threadPool= Executors.newFixedThreadPool(3);
// 创建任务
Runnable runnable=new Runnable() {
@Override
public void run() {
System.out.println("任务被执行,线程:"+Thread.currentThread().getName());
}
};
// 执行任务
threadPool.submit(runnable);
threadPool.execute(runnable);
threadPool.execute(runnable);
threadPool.execute(runnable);
}
}
执行结果:
2.通过Executors.newCachedThreadPool创建
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Description:
* 创建一个可缓存的线程池,若线程数超过任务处理所需的,缓存一段时间后会回收,
* 如果线程数不够,会创建新线程
* Date: 2022/10/29 16:14
**/
public class CreatThreadPoolDemo2 {
public static void main(String[] args) {
// 创建线程池
ExecutorService threadPool= Executors.newCachedThreadPool();
// 执行任务
for(int i=0;i<10;i++){
threadPool.execute(()->{
System.out.println("任务被执行,线程:"+Thread.currentThread().getName());
});
}
}
}
执行结果:
它创建了10个线程来执行任务。
3.通过Executors.newSingleThreadExecutor创建
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Description:创建只有一个线程的线程池,保证先进先出的顺序
* Date: 2022/10/29 16:21
**/
public class CreatThreadPoolDemo3 {
public static void main(String[] args) {
// 创建线程池
ExecutorService threadPool= Executors.newSingleThreadExecutor();
// 执行任务
for(int i=0;i<10;i++){
final int c=i; //在lambda表达式中变量必须是final类型
threadPool.execute(()->{
System.out.println("线程:"+Thread.currentThread().getName()+"执行任务"+c);
});
}
}
}
执行结果:
4.通过Executors.newScheduledThreadPool创建
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Description:一个可以执行延迟任务的线程池
* Date: 2022/10/29 16:39
**/
public class CreatThreadPoolDemo4 {
public static void main(String[] args) {
// 创建有5个线程的线程池
ScheduledExecutorService threadPool= Executors.newScheduledThreadPool(5);
// 添加任务(设置1s后执行)
System.out.println("任务添加时间:"+new Date());
threadPool.schedule(()->{
System.out.println("任务执行时间:"+new Date());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
}
}, 1, TimeUnit.SECONDS);
}
}
执行结果:
5通过Executors.newSingleThreadScheduledExecutor创建
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Description:单线程且可以执行延迟任务的线程池
* Date: 2022/10/29 16:51
**/
public class CreatThreadPoolDemo5 {
public static void main(String[] args) {
ScheduledExecutorService threadPool= Executors.newSingleThreadScheduledExecutor();
// 添加定时执行任务(2s 后执行)
System.out.println("添加任务时间:" + new Date());
threadPool.schedule(() -> {
System.out.println("任务被执行时间:" + new Date());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
}
}, 2, TimeUnit.SECONDS);
}
}
执行结果:
6.通过Executors.newWorkStealingPool创建(jdk1.8及之后的方法)
任务的执行顺序是不确定的
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Description:创建一个抢占式执行的线程池
* Date: 2022/10/29 16:55
**/
public class CreatThreadPoolDemo6 {
public static void main(String[] args) {
ExecutorService threadPool= Executors.newWorkStealingPool();
// 执行任务
for(int i=0;i<10;i++){
final int c=i;
threadPool.execute(()->{
System.out.println("线程:"+Thread.currentThread().getName()+"执行任务:"+c);
});
}
// 确保任务执行完成
while (!threadPool.isTerminated()){
}
}
}
执行结果:
二:通过ThreadPoolExecutor创建
1.通过ThreadPoolExecutor自定义线程池
public class CreatThreadPoolDemo7 {
public static void main(String[] args) {
ThreadPoolExecutor threadPool=new ThreadPoolExecutor(5,10,100, TimeUnit.SECONDS,new LinkedBlockingQueue<>(10));
// 执行任务
for(int i=0;i<10;i++){
final int c=i;
threadPool.execute(()->{
System.out.println("线程:"+Thread.currentThread().getName()+"执行任务:"+c);
});
}
}
}
ThreadPoolExecutor方法参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
1.corePoolSize
线程池的核心线程数,定义了最小可以同时运行的线程数量
2.maximumPoolSize
当队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数
3.workQueue
当新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,新任务就会被存放在队列中
4.keepAliveTime
当线程池中的线程数量大于 corePoolSize 的时候,如果这时没有新的任务提交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了 keepAliveTime才会被回收销毁
5.unit
keepAliveTime 参数的时间单位。
6.handler
饱和策略:有四种
(1)AbortPolicy:抛出异常来拒绝新任务
(2)callerRunsPolicy:在调用execute方法的线程中运行被拒绝的任务,这种策略会降低对于新任务提交速度,如果应用程序可以承受此延迟并且你要求任何一个任务请求都要被执行的话,你可以选择这个策略.
(3)DiscardOldestPolicy:丢弃最早的未处理的任务请求
(4)DiscardPolicy:不处理新任务,直接丢弃掉。
execute和submit的区别
1.都是线程池用来提交任务的方法,但是execute只能提交Runnable类型的任务,submit既能提交Runnable类型的任务也能提交Callable类型的任务。
2.execute()没有返回值,submit有返回值。
3.excute会直接任务执行时的抛出异常,可以用try、catch捕获,submit会吃掉异常,可通过Future的get方法将任务执行时的异常重新抛出