线程池:
线程池提供了一种限制和管理资源(包括执行一个任务)。每个线程池还维护一些基本统计信息,例如已完成任务的数量。
使用线程池的好处:
降低线程创建和销毁线程而产生的系统开销;
提高相应速度,创建相对从线程池里面取速度较快;
提高线程的可管理性:
常用的线程池有哪些:
newFixedThreadPool:创建固定大小(线程个数)的线程池
newSingleThreadPool:创建单线程的线程池
newscheduleThreadPool:创建具有时间的线程池
newCacheThreadPool:创建一个根据实际情况调整数量的线程池
如何创建一个线程池:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
/**
核心参数:
corePoolSize:线程池的核心线程最大数量
maximumPoolSize:线程池的最大线程数量
keepAliveTime:当线程池的数量大于corePoolSize时候,核心线程外的线程不会直接销毁而是等待,时间为keepAliveTime
unit:等待的时间的单位
workQueue:来的线程判断是否当前线程数量是否大于核心线程数量,满足条件的话进入等待队列
threadFactory:executor创建新的线程时候会用到
handler:线程的拒绝策略
*/
线程的饱和策略:拒绝策略:
如果当前运行的线程数量达到了最大线程并且队列也被放满的时候,此时线程就会做出相关的策略:
策略有如下几种:
- AbortPolicy:拒绝策略,丢弃任务并抛出异常
- DiscardPolicy:丢弃任务,不抛出异常
- DiscardOldPolicy:丢弃队列中末尾的任务,将当前任务提交给线程池
- CallerRunPolicy:交给调用线程池的线程进行处理(谁调用谁处理)
线程池的执行流程是什么?
- 提交一个任务,如果当前线程池存活的线程数小于核心线程数量,则会创建一个核心线程进行处理任务;
- 如果核心线程满了,即corePoolSize等于线程数,此时一个提交的新任务就会放入WorkQueue队列里等待;
- 如果核心线程满了,等待队列也满了,此时判断线程数是否大于maxinumPoolSize,小于的话创建一个非核心线程去处理任务;
- 最后满了的话,还会有先的线程进来,就会直接进行拒绝策略处理。
示例:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Demo1 {
private static final int CORE_POOL_SIZE = 3;//核心线程数量3个
private static final int MAX_POOL_SIZE = 6;//最大线程数量6
private static final int QUEUE_CAPACITY = 30;//任务队列30个
private static final Long KEEP_ALIVE_TIME = 2L;//等待时间
public static void main(String[] args) {
//使用阿里巴巴推荐的创建线程池的方式
//通过ThreadPoolExecutor构造函数自定义参数创建
ThreadPoolExecutor executor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(QUEUE_CAPACITY),
new ThreadPoolExecutor.CallerRunsPolicy());
for (int i = 0; i < 10; i++) {
//创建WorkerThread对象(WorkerThread类实现了Runnable 接口)
Runnable worker = new RunnableTest("" + i);
//执行Runnable
executor.execute(worker);
}
//终止线程池
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println("完成所有线程的处理");
}
}
import java.util.Date;
public class RunnableTest implements Runnable {
private String name;
public RunnableTest(String s) {
this.name = s;
}
@Override
public void run() {
//线程开始
System.out.println(Thread.currentThread().getName() + " 开始时间 = " + new Date());
moniculi();//模拟处理
//线程结束
System.out.println(Thread.currentThread().getName() + " 结束时间 = " + new Date());
}
private void moniculi() {
try {
Thread.sleep(3000);//睡三秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return this.name;
}
}
一次执行三个线程
executor执行的方法:
submit方法:
此方法提交需要返回值的任务,返回是一个Future对象,通过它可以判断线程是否执行成功
通过Future的get方法获取返回值,使用第一个会阻塞线程直到线程任务完成;而第二个方法会阻塞线程一段时间后返回,此时线程不一定执行完成任务。
execute方法:
此方法用于执行不用返回值的任务,所以无法进行判断线程是否被线程池成功执行与否;