课程名称:玩转Java并发工具,精通JUC,成为并发多面手
课程章节:第3章 线程池【治理线程的最大法宝】
课程讲师: 悟空
课程内容
fixedThreadPool
由于传进去的LinkedBlockingQueue是没有容量上限的,所以当请求越来越多,并且无法及时处理完毕的时候,也就是请求堆积的时候,会容易占用大量的内存,可能会导致OOM
public class Executors {
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads/*maximumPoolSize*/,
                0L/*既然不可能超过核心线程数,这个参数是没有意义的*/, TimeUnit.MILLISECONDS/*这个参数和keepAliveTime是绑定的*/,
                new LinkedBlockingQueue<Runnable>()/*无界队列,因为FixedThreadPool和SingleThreadExecutor线程数量是固定的,当任务多的时候不得不用一个无限多的队列帮助存储*/);
    }
}
fixedThreadPoolOOM异常示例
/**
 * 描述: 演示fixedThreadPool出错的情况
 */
public class FixedThreadPoolOOM {
    private static ExecutorService executorService = Executors.newFixedThreadPool(1);
    public static void main(String[] args) {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            executorService.execute(new SubThread());
        }
    }
}
class SubThread implements Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
运行结果:
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
	at java.util.concurrent.LinkedBlockingQueue.offer(LinkedBlockingQueue.java:416)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1371)
	at com.wkq.threadpool.FixedThreadPoolOOM.main(FixedThreadPoolOOM.java:14)
singleThreadExecutor
- 单线程的线程池:它只会用唯一的工作线程来执行任务
- 它的原理和FixedTreadPool是一样的,但是此时的线程数量被设置为了1
singleThreadPool的原理和fixedThreadPool基本一样,只不过把线程数直接设置成了1,所以这也会导致同样的问题,也就是当请求堆积的时候,可能会占用大量的内存。
public class Executors {
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
                (new ThreadPoolExecutor(1, 1,
                        0L, TimeUnit.MILLISECONDS,
                        new LinkedBlockingQueue<Runnable>()));
    }
}
3.3、 cachedThreadPool
- 可缓存线程池。
- 特点:无界线程池,具有自动回收多余线程的功能。
源码注释:Threads that have not been used for sixty seconds are terminated and removed from the cache。
Cache指的是对线程的缓存,如果一段时间线程空闲,就回收
public class Executors {
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                60L, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>()/*不需要队列存储任务,新的任务来了直接交给线程去执行,如果没有则创建非核心线程执行*/);
    }
}
这里的弊端在于第二个参数maximumPoolSize被设置为了Integer.MAX_VALUE,这可能会创建数量非常多的线程,甚至导致OOM。
scheduledThreadPool
- 支持定时及周期性的执行任务,做一些跟时间相关,跟推迟相关的工作
- 用来代替定时任务以及定时器都是可以的
public class ScheduledThreadPoolExecutor
        extends ThreadPoolExecutor
        implements ScheduledExecutorService {
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0/*它的任务是周期性的,所以不需要保留额外的线程,为0可以快速回收*/, NANOSECONDS,
                new DelayedWorkQueue()/*使用延迟队列,延迟队列的能力就是把它里面的任务根据时间先后去做延迟*/);
    }
}
示例:
public class ScheduledThreadPool {
    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/*单位*/);//周期性
    }
}
以上四种线程池的构造函数的参数
| Parameter | FixedThreadPool | CachedThreadPool | ScheduledThreadPool | SingleThreadPool | 
|---|---|---|---|---|
| corePoolSize | constructor-arg | 0 | constructor-arg | 1 | 
| maxPoolSize | same as corePoolSize | INTEGER.MAX_VALUE | INTEGER.MAX_VALUE | 1 | 
| keepAliveTime | 0 | 60s | 0 | 0 | 
| workQueue | LinkedBlocking | SynchronousQueue | DelayedWorkQueue | LinkedBlocking | 
学习收获
今天学习了常见的几种线程池的使用场景和用法,收获颇丰!
 
		 随时随地看视频
随时随地看视频 
				 
				 
				 
				