什么是线程池?
就是提前创建好了几个线程给他放到一个容器里,有任务需要执行时,出来一个线程执行任务,任务执行完了不销毁线程,然后放回去,等待下一次任务到来。
线程池的好处
- 降低创建线程和销毁线程的性能开销
- 提高响应速度,当有新任务需要执行是不需要等待线程创建就
可以立马执行- 合理的设置线程池大小可以避免因为线程数超过硬件资源瓶颈
带来的问题
Java提供的四种线程池
1、newCachedThreadPool:用来创建一个可以无限扩大的线程池,适用于负载较轻的场景,执行短期
异步任务。(可以使得任务快速得到执行,因为任务时间执行短,可以很快结束,也不会造成cpu过度
切换)
2、newFixedThreadPool:创建一个固定大小的线程池
3、newSingleThreadExecutor:创建一个单线程的线程池,适用于需要保证顺序执行各个任务。
4、newScheduledThreadPool:适用于执行延时或者周期性任务。
newFixedThreadPool:
固定大小的线程池,每次有任务就创建一个线程,直到线程达到线程池的最大值,后面的任务会放到一个队列里,等待线程空闲的时候执行
public class PoolDemo implements Runnable{
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(3);
for (int i = 0; i <100 ; i++) {
pool.execute(new PoolDemo() {
});
}
pool.shutdown();
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
代码结果
可以很清楚看见只有3个线程在运行,这就是线程池的好处,循环利用已有的线程。
newSingleThreadExecutor:
java线程池中单一的线程池。表示是一个线程池,可以添加多个子线程,但是只有一个线程能运行,当前线程执行完了后下一个添加进来的线程才能运行。单一的线程池,该线程池中每时每刻只有一个线程能运行。添加进入的线程必须等待当前执行的线程执行完了后,才能执行(依照先进先出)
public class PoolDemo implements Runnable{
public static void main(String[] args) {
ExecutorService pool = Executors.newSingleThreadExecutor();
for (int i = 0; i <100 ; i++) {
pool.execute(new PoolDemo() {
});
}
pool.shutdown();
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
这个就是只有一个线程。
newCachedThreadPool:
动态伸缩线程池,任务到来,回收空闲的线程,若没有空闲的,则新建
public class PoolDemo implements Runnable{
public static void main(String[] args) {
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i <100 ; i++) {
pool.execute(new PoolDemo() {
});
}
pool.shutdown();
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
newScheduledThreadPool:
周期性线程池
public class PoolDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
// 延迟3秒执行
System.out.println("延迟3秒执行,当前线程:" + Thread.currentThread().getName() + "当前任务时间:"
+ DateFormat.getTimeInstance().format(new Date()));
}
}, 3, TimeUnit.SECONDS);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
// 延迟1秒,每隔3秒执行
System.out.println("延迟1秒,每隔3秒执行,当前线程:" + Thread.currentThread().getName() + "当前任务时间:"
+DateFormat.getTimeInstance().format(new Date()));
}
}, 1, 3, TimeUnit.SECONDS);
}
}
如果大家查看源码会发现,前三个里面其实都是new ThreadPoolExecutor
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
区别只是这个ThreadPoolExecutor后面参数不一样而已
ThreadPoolExecutor(int corePoolSize,//核心线程数
int maximumPoolSize,//最大线程数
long keepAliveTime,//线程存活时间
TimeUnit unit,
BlockingQueue<Runnable> workQueue,//任务队列
ThreadFactory threadFactory,//线程创建工厂
RejectedExecutionHandler handler) //饱和策略
有返回值的线程池
public class CallableFutureDemo implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("hello");
Thread.sleep(3000);
return "你好";
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(1);
CallableFutureDemo callableFutureDemo = new CallableFutureDemo();
FutureTask futureTask = (FutureTask)executorService.submit(callableFutureDemo);
System.out.println(futureTask.get());
}
}
线程池监控
自己新建一个Exectors ,然后去把源码复制一个
public class Exectors {
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolSelf(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
}
然后新建一个ThreadPoolSelf继承ThreadPoolExecutor,重写shutdown,beforeExecute,afterExecute。
public class ThreadPoolSelf extends ThreadPoolExecutor {
public ThreadPoolSelf(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
@Override
public void shutdown() {
super.shutdown();
}
@Override
protected void beforeExecute(Thread t, Runnable r) {
System.out.println(Thread.currentThread().getName()+"线程开始时间:"+ DateFormat.getTimeInstance().format(new Date()));
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
System.out.println("初始线程数:"+this.getPoolSize());
System.out.println("核心线程数:"+this.getCorePoolSize());
System.out.println("正在执行的任务数量:"+this.getActiveCount());
System.out.println("已经执行的任务数量:"+this.getCompletedTaskCount());
System.out.println("任务总数:"+this.getTaskCount());
}
}
然后就可以把我们需要的信息打印出来了。
public class PoolDemo implements Runnable{
public static void main(String[] args) {
ThreadPoolExecutor pool = (ThreadPoolExecutor) Exectors.newFixedThreadPool(3);
//可以提前预热所有核心线程
pool.prestartAllCoreThreads();
for (int i = 0; i <100 ; i++) {
pool.execute(new PoolDemo() {
});
}
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}