线程池的简单的demo实现:
用户注册成功后发送消息给他,这个消息可以是异步发送的,所以先将用户保存在一个阻塞队列中,使用线程异步发送消息
package com.syp.redisson.executorDemo;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @Author: SYP
* @Date: 2020/8/15
* @Description:
*/
public class ExecutorDemo {
ExecutorService executorService = Executors.newSingleThreadExecutor();
ExecutorService executorService2 = Executors.newCachedThreadPool();
ExecutorService executorService3 = Executors.newFixedThreadPool(4);
ExecutorService executorService4 = Executors.newScheduledThreadPool(4);
ArrayBlockingQueue<User> arrayBlockingQueue = new ArrayBlockingQueue<User>(10);
public static void main(String[] args) throws InterruptedException {
ExecutorDemo executorDemo = new ExecutorDemo();
executorDemo.init();
for(int i=0; i<1000; i++){
Thread.sleep(2000);
executorDemo.register("user_"+i);
}
}
public void init(){
executorService.execute(() -> {
while (true) {
try {
User user = arrayBlockingQueue.take();
sendMsg(user);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
public void register(String name){
User user = new User(name);
try {
System.out.println("给"+user.getName()+"注册成功");
arrayBlockingQueue.put(user);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void sendMsg(User user){
System.out.println("给"+user.getName()+"发送消息");
}
}
先上一张线程池execute方法执行流程图:
使用hashSet存储工作线程:
private final HashSet workers = new HashSet();
接下来看源码吧
线程池参数:
int corePoolSize, //核心线程数
int maximumPoolSize, //最大线程数
long keepAliveTime, //临时工作线程的存活时间
TimeUnit unit, //存活单位
BlockingQueue<Runnable> workQueue, //阻塞队列
ThreadFactory threadFactory, //线程工厂
RejectedExecutionHandler handler //拒绝策略
常用的线程池类型:
1.只有一个核心线程的线程池
ExecutorService executorService = Executors.newSingleThreadExecutor();
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
- 可以无限新建工作线程的线程池,适合执行时间较短的任务
ExecutorService executorService2 = Executors.newCachedThreadPool();
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
3.可配置线程数量的线程池,固定线程数
ExecutorService executorService3 = Executors.newFixedThreadPool(4);
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
4.任务调度型,可延迟执行,用于心跳检测等
ExecutorService executorService4 = Executors.newScheduledThreadPool(4);
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
线程池在创建的时候并没有初始化核心线程,新增任务的时候会视情况创建
executorService.execute()
这里的三步注释解释的很清楚,可以参考流程图一起看
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
//工作线程数量小于核心线程数量 新建工作线程
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
//如果工作线程大于核心线程数,则把任务添加到阻塞队列中
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//如果阻塞队列满了 并且线程数达到最大线程数,则执行拒绝策略
else if (!addWorker(command, false))
reject(command);
}
32位 高三位线程状态,低29位线程数量
新建工作线程
addWorker()
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
//如果新建核心线程,则比较核心线程数,否则比较最大线程数
//工作线程数量大于核心线程或者最大线程时,添加失败
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//CAS 增加线程数量
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
//添加线程到线程池中 workers是一个hashSet
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
//启动工作线程
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
//如果线程添加失败,这里会做个回滚操作,移除工作线程,修改线程数量
addWorkerFailed(w);
}
return workerStarted;
}
拒绝策略4种:
1.把目标任务的run()方法,当作普通方法直接调用
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
2.抛出异常
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
3.将最老的一个任务丢掉,执行新的任务
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
4.什么都不做
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
Worker的run()方法
我们传过来的是一个线程,但是并没有作为线程启动,而是在工作线程的run方法里把目标任务的run()方法当做普通方法调用了, task.run() 而不是start() ,
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock(); //这里加锁,是为了阻止线程中断
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
线程的复用和回收是怎么体现的呢?
线程的复用体现在 worker线程在runWorker方法中
while (task != null || (task = getTask()) != null){
…
task.run()
…
}
循环从阻塞队列中获取任务,去执行
临时线程的销毁: 如果当前工作线程大于核心线程或设置了超时,获取任务时调用 workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) ,超过时间,没有拿到任务,该线程就会被回收。否则会一直阻塞等待任务workQueue.take();
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
如何设置线程池大小
cpu密集型: cpu核心数
io密集型: cpu核心数的2倍