java线程池,一篇治愈你的迷茫
2018-01-23 16:25
190 查看
今天回忆一下线程池的前世今生
内容有一下几点:
为什么要用线程池线程池的核心类 ThreadPoolExecutor
Executors 类提供的几种常见的线程池
开始正事了
一、为什么要用线程池
1、创建和销毁线程是有消耗的,如果 创建线程的时间t1、销毁线的时间t2、线程执行的时间t3他们之间的关系是t1+t2>t3,我们就认为他们是不划算的。这样的问题可以用线程池完美解决,缓存一些线程到线程池,使用的时候从线程池中取,使用完毕就释放会线程池。这就是线程池的思想,很简单吧。 2、当线程过多是后,他们会抢占资源,会出现诡异而不可预测的事情(阻塞等),使用线程池可以避免这样的情况发生,同时可以方便的管理线程(延时执行,定时循环执行)。
二、ThreadPoolExecutor 的前世今生
1、ThreadPoolExecutor 主要有四个构造方法如下
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), handler); }
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler); }
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { }
参数有点多,不要怕,下面一一解释一下这些参数的含义。
1、 int corePoolSize: 该线程池最大核心线程数量。
核心线程:新建线程的时候,如果线程数量小于核心线程最大数量的时候,新建的是核心线程数量,如果大于和弦线程最大数量的时候,新建的就是非核心线程数量。 核心线程默认会一直存活下去,哪怕是这个线程闲置下来什么也不干。 如果指定ThreadPoolExecutor的allowCoreThreadTimeOut这个属性为true,那么核心线程如果不干活(闲置状态)的话,超过一定时间(时长下面参数决定),就会被销毁掉 简单的就不多做解释了,继续往下看吧。
2、int maximumPoolSize:该线程池中允许最大的线程数。
最大核心线程数量+非核心数量=最大的线程数 小学的数学算数,相信你能算对。
3、long keepAliveTime :存活时间
非核心线程闲置下来,经过keepAliveTime 这个时间就会被销毁。 如果ThreadPoolExecutor的allowCoreThreadTimeOut这个属性为true,那么这个也将作用于核心线程。
4、TimeUnit unit : 时间单位
java中通用的时间单位如下:
NANOSECONDS : 1微毫秒 = 1微秒 / 1000 MICROSECONDS : 1微秒 = 1毫秒 / 1000 MILLISECONDS : 1毫秒 = 1秒 /1000 SECONDS : 秒 MINUTES : 分 HOURS : 小时 DAYS : 天
5、BlockingQueue workQueue :阻塞队里,这个大有名堂,好好说一下。
队列有好些中,下面是详解
SynchronousQueue:这个队列接收到任务的时候,会直接提交给线程处理,而不保留它,如果所有线程都在工作怎么办?那就新建一个线程来处理这个任务!所以为了保证不出现<线程数达到了maximumPoolSize而不能新建线程>的错误,使用这个类型队列的时候,maximumPoolSize一般指定成Integer.MAX_VALUE,即无限大
LinkedBlockingQueue:这个队列接收到任务的时候,如果当前线程数小于核心线程数,则新建线程(核心线程)处理任务;如果当前线程数等于核心线程数,则进入队列等待。由于这个队列没有最大值限制,即所有超过核心线程数的任务都将被添加到队列中,这也就导致了maximumPoolSize的设定失效,因为总线程数永远不会超过corePoolSize。
ArrayBlockingQueue:可以限定队列的长度,接收到任务的时候,如果没有达到corePoolSize的值,则新建线程(核心线程)执行任务,如果达到了,则入队等候,如果队列已满,则新建线程(非核心线程)执行任务,又如果总线程数到了maximumPoolSize,并且队列也满了,则发生错误
DelayQueue:队列内元素必须实现Delayed接口,这就意味着你传进去的任务必须先实现Delayed接口。这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务
6、ThreadFactory threadFactory:创建线程工厂
这是一个接口,源码如下:
public interface ThreadFactory { /** * Constructs a new {@code Thread}. Implementations may also initialize * priority, name, daemon status, {@code ThreadGroup}, etc. * * @param r a runnable to be executed by new thread instance * @return constructed thread, or {@code null} if the request to * create a thread is rejected */ Thread newThread(Runnable r); }
子类实现这个方法,具体实现新建的线程的过程,认为麻烦的可以略过,有默认的。
7、RejectedExecutionHandler handler:异常处理的handler
这个是专门处理异常的,上面说到的抛出异常都是这里处理的,有默认的。
参数讲完了,是不是soso easy。
还有一个方法:
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); 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); }
这个方法就是添加线程的方法。
三、常见的线程池
1、cachedThreadPool:无限大小的线程池
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory); }
2、FixedThreadPool:固定大小的线程池
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory); }
3、SingleThread:单线程的线程池
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory)); }
4、ScheduledThreadPool:能时间调度的的线程池
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } public static ScheduledExecutorService newScheduledThreadPool( int corePoolSize, ThreadFactory threadFactory) { return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); }
源码贴出来,很容易看出,致谢都是对ThreadPoolExecutor 构造方法的灵活应用,比对一下参数,这几种线程池的特性就很清楚了。
来来,你是不是可以自己组装自己特性的线程池了。
相关文章推荐
- 一篇好文,以在迷茫时阅读
- 一篇好文,以在迷茫时阅读
- 一篇好文,以在迷茫时阅读
- 一篇好文,以在迷茫时阅读
- 一篇好文,以在迷茫时阅读(中国惠普前总裁孙振耀的毕生经验)
- 一篇好文,以在迷茫时阅读
- 一篇好文,以在迷茫时阅读
- 一篇好文,以在迷茫时阅读
- 一篇好文,以在迷茫时阅读
- 一篇好文,以在迷茫时阅读
- 【转】一篇好文,以在迷茫时阅读
- 一篇好文,以在迷茫时阅读
- [转]一篇好文,以在迷茫时阅读
- 一篇好文,以在迷茫时阅读
- (转)一篇好文,以在迷茫时阅读
- [转]一篇好文,以在迷茫时阅读
- 分享一篇日志,与迷茫中的你,生命如此短暂
- ConcurrentHashMap一篇治愈你的迷茫
- 一篇好文,以在迷茫时阅读
- 一篇好文,找工作迷茫时可以看看