- 浏览: 491633 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
herofighter2008:
图呢?图呢?图呢?图呢?
BlockingQueue -
zy13608089849:
请问一下博主,文中几处提到的图,怎么都没有?是我这显示不出来还 ...
BlockingQueue -
swift911:
在短信的场景下很好用,感谢分享
BlockingQueue -
tony_0529:
学习了~谢谢分享。
BlockingQueue -
Master-Gao:
...
BlockingQueue
前记: 查看JDK帮助文档,可以发现该类比较简单,继承自AbstractExecutorService,而AbstractExecutorService实现了ExecutorService接口。 ThreadPoolExecutor的完整构造方法的签名是: 先记着,后面慢慢解释。 ===============================神奇分割线================================== 其实对于ThreadPoolExecutor的构造函数网上有N多的解释的,大多讲得都很好,不过我想先换个方式,从Executors这个类入手。因为他的几个构造工厂构造方法名字取得令人很容易了解有什么特点。但是其实Executors类的底层实现便是ThreadPoolExecutor! ThreadPoolExecutor是Executors类的底层实现。 在JDK帮助文档中,有如此一段话: “强烈建议程序员使用较为方便的 ===============================神奇分割线================================== OK,那就来看看源码吧,从newFixedThreadPool开始。 ExecutorService newFixedThreadPool(int nThreads):固定大小线程池。 可以看到,corePoolSize和maximumPoolSize的大小是一样的(实际上,后面会介绍,如果使用无界queue的话maximumPoolSize参数是没有意义的),keepAliveTime和unit的设值表名什么?-就是该实现不想keep alive!最后的BlockingQueue选择了LinkedBlockingQueue,该queue有一个特点,他是无界的。 ExecutorService newSingleThreadExecutor():单线程。 可以看到,与fixedThreadPool很像,只不过fixedThreadPool中的入参直接退化为1 ExecutorService newCachedThreadPool():无界线程池,可以进行自动线程回收。 这个实现就有意思了。首先是无界的线程池,所以我们可以发现maximumPoolSize为big big。其次BlockingQueue的选择上使用SynchronousQueue。可能对于该BlockingQueue有些陌生,简单说:该QUEUE中,每个插入操作必须等待另一个 线程的对应移除操作。比如,我先添加一个元素,接下来如果继续想尝试添加则会阻塞,直到另一个线程取走一个元素,反之亦然。(想到什么?就是缓冲区为1的生产者消费者模式^_^) 注意到介绍中的自动回收线程的特性吗,为什么呢?先不说,但注意到该实现中corePoolSize和maximumPoolSize的大小不同。 ===============================神奇分割线================================== 到此如果有很多疑问,那是必然了(除非你也很了解了) 先从BlockingQueue<Runnable> workQueue这个入参开始说起。在JDK中,其实已经说得很清楚了,一共有三种类型的queue。以下为引用:(我会稍微修改一下,并用红色突出显示) ===============================神奇分割线================================== 到这里,该了解的理论已经够多了,可以调节的就是corePoolSize和maximumPoolSizes 这对参数还有就是BlockingQueue的选择。 例子一:使用直接提交策略,也即SynchronousQueue。 首先SynchronousQueue是无界的,也就是说他存数任务的能力是没有限制的,但是由于该Queue本身的特性,在某次添加元素后必须等待其他线程取走后才能继续添加。在这里不是核心线程便是新创建的线程,但是我们试想一样下,下面的场景。 我们使用一下参数构造ThreadPoolExecutor: 当核心线程已经有2个正在运行. OK,此时任务变加入队列之中了,那什么时候才会添加新线程呢? 这里就很有意思了,可能会出现无法加入队列吗?不像SynchronousQueue那样有其自身的特点,对于无界队列来说,总是可以加入的(资源耗尽,当然另当别论)。换句说,永远也不会触发产生新的线程!corePoolSize大小的线程数会一直运行,忙完当前的,就从队列中拿任务开始运行。所以要防止任务疯长,比如任务运行的实行比较长,而添加任务的速度远远超过处理任务的时间,而且还不断增加,如果任务内存大一些,不一会儿就爆了,呵呵。 可以仔细想想哈。 例子三:有界队列,使用 这个是最为复杂的使用,所以JDK不推荐使用也有些道理。与上面的相比,最大的特点便是可以防止资源耗尽的情况发生。 举例来说,请看如下构造方法: 假设,所有的任务都永远无法执行完。 对于首先来的A,B来说直接运行,接下来,如果来了C,D,他们会被放到queu中,如果接下来再来E,F,则增加线程运行E,F。但是如果再来任务,队列无法再接受了,线程数也到达最大的限制了,所以就会使用拒绝策略来处理。 总结:
一、ThreadPoolExecutor使用和思考(上)-线程池大小设置与BlockingQueue的三种实现区别
LinkedBlockingQueue,
ArrayBlockingQueue
);中篇中主要聊聊与keepAliveTime这个参数相关的话题;下片中介绍一下一些比较少用的该类的API,及他的近亲:ScheduledThreadPoolExecutor。
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler)
Executors
工厂方法 Executors.newCachedThreadPool()
(无界线程池,可以进行自动线程回收)、Executors.newFixedThreadPool(int)
(固定大小线程池)和Executors.newSingleThreadExecutor()
(单个后台线程),它们均为大多数使用场景预定义了设置。”可以推断出ThreadPoolExecutor与Executors类必然关系密切。
BlockingQueue
都可用于传输和保持提交的任务。可以使用此队列与池大小进行交互:
SynchronousQueue
,它将任务直接提交给线程而不保持它们。在此,如果不存在可用于立即运行任务的线程,则试图把任务加入队列将失败,因此会构造一个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。直接提交通常要求无界 maximumPoolSizes 以避免拒绝新提交的任务。当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。LinkedBlockingQueue
)将导致在所有 corePoolSize 线程都忙时新任务在队列中等待。这样,创建的线程就不会超过 corePoolSize。(因此,maximumPoolSize 的值也就无效了。)当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。ArrayBlockingQueue
)有助于防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。如果任务频繁阻塞(例如,如果它们是 I/O 边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,CPU 使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量。
LinkedBlockingQueue
ArrayBlockingQueue。
RejectedExecutionException
发表评论
-
HashMap的非线程安全
2013-11-25 16:06 878在平时开发中,我们经常采用HashMap来作为本地缓存的一种 ... -
SynchronousQueue
2012-08-11 23:30 13238SynchronousQueue是这样一种阻塞队列,其中每个 ... -
Java Atomic
2012-05-09 21:13 4161我们知道volatile修饰的变量可以实现基本的加载和赋值的原 ... -
ArrayList线程不安全分析
2012-04-22 17:49 8580一个 ArrayList ,在添加一个元素的时候,它可能会有两 ... -
ConcurrentModificationException
2012-04-22 16:38 1289如果在获得了某个集合的迭代器之后,除了通过这个迭代器之外对该集 ... -
LinkedBlockingQueue和ConcurrentLinkedQueue
2012-04-21 14:19 80041.LinkedBlockingQueue<E>: ... -
(转)深入研究ReentrantLock(重入锁)之引出话题篇
2012-04-20 20:28 1154一直以来都想好好研究下ReentrantLock,她的独到魅力 ... -
ReentrantLock和synchronized的区别随笔
2012-04-20 20:27 2413可重入锁 ReentrantLock 的含义是: ... -
(转)ReentrantLock和synchronized两种锁定机制的对比
2012-04-20 20:07 1004多线程和并发性并不是什么新内容,但是 Java 语言设计中的创 ... -
volatile变量
2012-02-20 21:26 1786我们知道,在Java中设置变量值的操作,除了long和doub ... -
(转)java并发编程-Executor框架
2012-01-17 09:42 976Executor框架是指java 5中引入的一系列并发库中 ... -
ThreadLocal的几种误区
2011-11-05 22:54 906最近由于需要用到ThreadLocal,在网上搜索 ... -
正确理解ThreadLocal
2011-11-05 22:41 1275首先, ThreadLocal 不是用来解决 ...
相关推荐
ThreadPoolExecutor源码解析.pdf
(转)线程池:java_util_ThreadPoolExecutor 比较详细的介绍了ThreadPoolExecutor用法与属性
ThreadPoolExecutor源码解析.md
ThreadPoolExecutor使用和思考
ThreadPoolExecutor线程池,有详尽介绍,本人进行过测试,可以使用
在《阿里巴巴java开发手册》中...另外由于前面几种方法内部也是通过ThreadPoolExecutor方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险。
一个关于java 线程池的例子,也适合android
线程池ThreadPoolExecutor实战及其原理分析(下)线程池ThreadPoolExecutor实战及其原理分析(下)线程池ThreadPoolExecutor实战及其原理分析(下)线程池ThreadPoolExecutor实战及其原理分析(下)线程池ThreadPoolExecutor...
ThreadPoolExecutor的使用和Android常见的4种线程池使用介绍
线程池的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,那么超出数量的线程排队等候,等其他线程执行完毕再从队列中取出任务来执行。...
1.资源简介:PyQt5中使用多线程模块QThread解决了PyQt5界面程序执行比较耗时操作时,程序卡顿出现的无响应以及界面输出无法实时显示的问题,采用线程池ThreadPoolExecutor解决了ping多个IP多任务耗时问题。...
NULL 博文链接:https://bijian1013.iteye.com/blog/2284676
线程池原理-ThreadPoolExecutor源码解析 1.构造方法及参数 2.阻塞对列: BlockingQueue 3.线程工厂: DefaultThreadFactory 4.拒绝策略: RejectedExecutionHandler 5.执行线程 Executor
死磕ThreadPoolExecutor线程池.pdf!!死磕ThreadPoolExecutor线程池.pdf死磕ThreadPoolExecutor线程池.pdf死磕ThreadPoolExecutor线程池.pdf
介绍ThreadPoolExecutor中池和queue配合使用的机制
JDK1[1].5中的线程池(ThreadPoolExecutor)使用简介
线程池ThreadPoolExecutor底层原理源码分析
JDK1.5中的线程池(java.util.concurrent.ThreadPoolExecutor)使用
Android中的线程池ThreadPoolExecutor解决了单线程下载数据的效率慢和线程阻塞的的问题,它的应用也是优化实现的方式。所以它的重要性不言而喻,但是它的复杂性也大,理解上可能会有问题,不过作为安卓工程师,了解...