概述
创建线程本身开销大,反复创建并销毁,过多的占用内存。所以有大量线程创建考虑使用线程池。线程池不用反复创建线程达到线程的复用,更具配置合理利用cpu和内存减少了开销,性能会得到提高,还能统一管理任务
比如服务器收到大量请求,每个请求都分配线程去处理,对服务器性能考验就比较大,如果创建5个以上线程考虑使用线程池。
线程复用原理
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
//获取线程池的线程
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//如过task不等于null,或者获取的task不为空
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);
}
}
线程数量:
cpu密集型(加密,计算hash等):cpu核心数1到2倍左右
耗时IO型(读写数据库,文件网络读写)一般是cpu核心数多倍充分利用cpu
线程数公式:cpu核心数x(1+平均等待时间/平均工作时间)
线程池创建
线程池创建使用线程工具类创建
//线程池顶层接口
public interface Executor {
void execute(Runnable command);
一般我们用Executor实现接口创建线程池
public interface ExecutorService extends Executor{
//重要方法
/**
* 初始化关闭过程,并不会直接关闭,在任务执行完毕后关闭,
* 不在增加新任务
*/
void shutdown();
/**
* 判断线程池是否已经关闭的状态,关闭返回true,否则返回false
*/
boolean isShutdown();
/**
* 判断线程是否已经完全终止,任务已经执行完毕
*/
boolean isTerminated();
/**
* 等待一定时间线程是否终止,执行完毕返回true,否则返回false
*
* @throws InterruptedException 如果期间被打断
*/
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
}
/**
* 停止所有正在执行的任务,停止处理等待的任务,并返回等待执行的任务列
* 表。
*
* @return 返回一个集合并返回
*/
List<Runnable> shutdownNow();
}
/**
* 线程池工具类,用来创建线程池,提供四个静态方法创建不同的线程池·
*返回 ExecutorService实现类也就是线程池对象(ThreadPoolExecutor)
*
*/
public class Executors {
}
//案例
private static ExecutorService executorService = Executors.newFixedThreadPool(1);
//提交任务,Task为一个具体线程类
executorService.execute(new Task());
ExecutorService实现类(ThreadPoolExecutor)构造方法参数解析
public ThreadPoolExecutor(int corePoolSize, //核心线程数
//最大线程数
int maximumPoolSize,
//线程保持存活时间,如果线程数多余核心数
//量而且限制,会回收闲置的线程
long keepAliveTime,
//时间单位
TimeUnit unit,
//任务存储队列
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
//ThreadFactory是当线程池需要创建新线程底层使用线程工厂
//创建,Handler是 线程无法接受新的任务的拒绝策略
Executors.defaultThreadFactory(), defaultHandler);
}
参数执行流程:
任务进来,核心线程处理,任务数多于核心数,将任务放进队列中,队列满了就创建新的线程但是线程总数小于最大线程数,如果任务多余最大线程数,就执行拒绝策略,不在接受任务
拒绝策略
- 线程池已经关闭,提交任务会失败
- 任务队列满了而且线程数线程数已经到了最大线程数提交任务失败
拒绝策略分类 - AbortPolicy()默认的策略,直接抛出异常
- DiscardPolicy()直接默默丢弃
- DiscardOldestPolicy()队列最老的丢弃
- CallerRunsPolicy()谁提交线程谁去执行发,比较人性化,给线程池反冲
如果核心线程数等于最大线程数就会创建固定的线程数的线程池,默认线程工厂能解决大部分情况
Executors创建线程的四个静态方法
更具业务场景选择合适的线程池
/**
* 创建固定大小的线程数量量的线程池,核心数量等于最大数量
* 都是nThreads,存活时间为0没有意义,无界队列,请求越来越多
* 就会进入队列,容易OOM(内存溢出)
*
* @param 线程数量
* @return 返回线程池
* @throws IllegalArgumentException 参数异常
*/
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
/**
*创建一个只有一个线程的线程池,同样容易OOM
*
* @return 返回线程池
*/
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
/**
* 核心数为0,最大线程数为Integer.MAX_VALUE,无论多少任务过来都会新建
* 线程去处理,60秒会回收闲置的线程,同样容易OOM
*
* @return 返回线程池
*/
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
/**
* 该线程池可以安排命令在给定延迟后运行或定期执行。同样容易OOM
* @param 核心数
* @return 返回线程池
* @throws 参数异常
*/
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
public static void main(String[] args) {
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(10);
//延迟五秒执行
// threadPool.schedule(new Task(), 5, TimeUnit.SECONDS);
//延迟一秒秒执行,每隔三秒执行一次
threadPool.scheduleAtFixedRate(new Task(), 1, 3, TimeUnit.SECONDS);
}
正确创建线程池的方式
言外之意就是默认四种创建线程池的方式是不正确的,首先默认的灵活度不够,难以适应各种业务场景,而且容易OOM,阿里巴巴编程规范明确规定不要用默认的方式创建线程池,而是直接用ThreadPoolExecutor这个实现类
最佳实践:
ThreadPoolExecutor poolExecutor=new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler)
poolExecutor.execute(Task);
//自定义线程池
/**
* 描述: 演示每个任务执行前后放执行逻辑
*/
public class PauseableThreadPool extends ThreadPoolExecutor {
//声明一个锁
private final ReentrantLock lock = new ReentrantLock();
//阻塞工具
private Condition unpaused = lock.newCondition();
//标志位
private boolean isPaused;
//一系列重写构造方法
public PauseableThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
public PauseableThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
}
public PauseableThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
}
public PauseableThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory,
handler);
}
//每次任务执行都会执行这个方法
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
lock.lock();
try {
while (isPaused) {
//阻塞线程池
unpaused.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
private void pause() {
lock.lock();
try {
isPaused = true;
} finally {
lock.unlock();
}
}
public void resume() {
lock.lock();
try {
isPaused = false;
//唤醒线程池
unpaused.signalAll();
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
PauseableThreadPool pauseableThreadPool = new PauseableThreadPool(10, 20, 10l,
TimeUnit.SECONDS, new LinkedBlockingQueue<>());
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("我被执行");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
for (int i = 0; i < 10000; i++) {
pauseableThreadPool.execute(runnable);
}
Thread.sleep(1500);
pauseableThreadPool.pause();
System.out.println("线程池被暂停了");
Thread.sleep(1500);
pauseableThreadPool.resume();
System.out.println("线程池被恢复了");
}
}
线程池状态
- RUNNING :接受任务并处理排队任务
- SHUTDOWN :不接受新任务,但处理排队任务
- STOP:不接受新任务,也不处理任务,突然终止
- TIDYING:任务都终止,运行terminate终止线程池
- TERMINATED:terminate()线程池不在启动