一、了解 ThreadPoolExecutor 方法内参数
ExecutorService executorService = new ThreadPoolExecutor(4,
6,
0L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(512),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
1、核心线程数
2、最大线程数
3、非核心线程闲置超时销毁时长(0L:long类型)
4、非核心线程闲置超时销毁时长单位(天,时,分,秒,毫秒......)
5、workQueue:(一般是用LinkedBlockingQueue)
-
SynchronousQueue:这个队列接收到任务的时候,会直接提交给线程处理,而不保留它,如果所有线程都在工作怎么办?那就新建一个线程来处理这个任务!所以为了保证不出现<线程数达到了maximumPoolSize而不能新建线程>的错误,使用这个类型队列的时候,maximumPoolSize一般指定成Integer.MAX_VALUE,即无限大
-
LinkedBlockingQueue:这个队列接收到任务的时候,如果当前线程数小于核心线程数,则新建线程(核心线程)处理任务;如果当前线程数等于核心线程数,则进入队列等待。由于这个队列没有最大值限制,即所有超过核心线程数的任务都将被添加到队列中,这也就导致了maximumPoolSize的设定失效,因为总线程数永远不会超过corePoolSize
-
ArrayBlockingQueue:可以限定队列的长度,接收到任务的时候,如果没有达到corePoolSize的值,则新建线程(核心线程)执行任务,如果达到了,则入队等候,如果队列已满,则新建线程(非核心线程)执行任务,又如果总线程数到了maximumPoolSize,并且队列也满了,则发生错误
-
DelayQueue:队列内元素必须实现Delayed接口,这就意味着你传进去的任务必须先实现Delayed接口。这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务
6、生产线程工厂类型(可以自定义)我这里使用了Executors.defaultThreadFactory(),不用Executors的四种线程池,那就用默认线程工厂吧。
7、拒绝策略 RejectedExecutionHandler handler
-
AbortPolicy:丢弃任务并抛出RejectedExecutionException
-
CallerRunsPolicy:只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务。显然这样做不会真的丢弃任务,但是,任务提交线程的性能极有可能会急剧下降。
-
DiscardOldestPolicy:丢弃队列中最老的一个请求,也就是即将被执行的一个任务,并尝试再次提交当前任务。
-
DiscardPolicy:丢弃任务,不做任何处理。
二、ThreadPoolExecutor的策略
上面介绍参数的时候其实已经说到了ThreadPoolExecutor执行的策略,这里给总结一下,当一个任务被添加进线程池时:
- 线程数量未达到corePoolSize,则新建一个线程(核心线程)执行任务
- 线程数量达到了corePools,则将任务移入队列等待
- 队列已满,新建线程(非核心线程)执行任务
- 队列已满,总线程数又达到了maximumPoolSize,就会由上面那位星期天(RejectedExecutionHandler)抛出异常
三、使用 ExecutorService 线程池抢票
import java.util.concurrent.*;
public class Test1{
public static void main(String[] args) throws Exception{
ExecutorService executorService = new ThreadPoolExecutor(4,
6,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(512),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
BuyTicket buyTicket=new BuyTicket();
for (int i = 0; i < 3000; i++) {
executorService.execute(buyTicket);
}
executorService.shutdown();
}
}
class BuyTicket implements Runnable{
private int ticketNum=300;
@Override
public void run(){
try {
Thread.sleep(10);
synchronized (this) {
if(ticketNum>0){
ticketNum--;
System.out.println(Thread.currentThread().getName()+"线程抢到一张票,票剩余"+ticketNum);
}else {
System.out.println("没票了");
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
三、运行结果
其他基础:
synchronized锁住的是括号里的对象,而不是代码。
其他:
//同时启动1000个线程,去进行i++计算,看看实际结果
for (int i = 0; i < 1000; i++) {
HashSet<Object> list = new HashSet<>();
Map<String, Object> map = new HashMap<>();
map.put("count", i);
list.add(map);
new Thread(() -> {
//listMapToMap(list);
getDatabaseData().put("count", list);
readDatabaseData();
}).start();
}