java 线程池相关

在java并发包中提供了线程池相关的API


主要有Executor、ExectorService接口,ThreadPoolExecutor、ScheduledThreadPoolExecutor类,Executors工具类,CompletionService接口、ExecutorCompletionService类,Callable、Future接口、FutureTask类等。以下简要画了个UML图:

Java.util.concurrent包学习(一) <wbr>线程池

线程池的基本思想:线程频繁的创建、销毁会极大地占用系统资源,为了减少系统在创建销毁线程时的开销,线程池应运而生。线程池包括多个已创建的线程,当有任务要在新线程中执行时,将任务提交给线程池,线程池选取空闲线程或新开线程执行该任务,可见线程池应维护一个任务队列和线程队列。此外还要对线程最大数、最小数目、空闲等待时间等进行管理。

线程池的组成(百度百科)

1、线程池管理器(ThreadPoolManager):用于创建并管理线程池
2、工作线程(WorkThread): 线程池中线程
3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行。
4、任务队列:用于存放没有处理的任务。提供一种缓冲机制。
 
API
 
1、Executor、ExecutorService接口(线程池
 
Executor提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法。
方法execute()向线程池提交任务
ExecutorService接口 一个ExecutorService包括运行、关闭、终止三个生命阶段,当一个ExecutorService处于关闭状态时,不能再向线程池提交任务。线程池管理,提交任务功能扩展submit
AbstractExecutorService实现了ExecutorService接口 ,ThreadPoolExecutor、ScheduledThreadPoolExecutor类是具体的线程池实现类
 
2、CompletionService接口、ExecutorCompletionService类
能返回已完成任务,维护一个已完成任务队列(Future),通过take() 函数可以获得任务。
CompletionService接口将生产新的异步任务与使用已完成任务的结果分离开来的服务。生产者 submit 执行的任务。使用者 take 已完成的任务,并按照完成这些任务的顺序处理它们的结果。
ExecutorCompletionService类 依赖于一个线程池对象Excutor,在一个Excutor基础上维护一个已完成任务队列。
 
3、Callable/Runnable、Future(任务接口),
(1)Callable是能够返回结果的可执行任务,Runnable不返回执行结果。文档中说Future 表示异步计算的结果,从CompletionService接口来理解,感觉不如说Future是执行完之后,包含返回结果且可以取消的任务。
(2)execute方法只能提交Runnable任务,ExecutorService接口扩展的submit方法还可以提交Callable任务,ExecutorCompletionService类的submit也支持两种任务
(3)FutrueTask实现了RunnableFuture接口,且可以由一个Callable对象来构造,基本包括了三个接口的功能
 
4、Executors(创建线程池
类提供了用于此包中所提供的执行程序服务的工厂方法。



并发包中提供了几个用于线程同步的类


1、CountDownLatch

一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

CountDownLatch 是一个通用同步工具,它有很多用途。

计数 1 初始化的 CountDownLatch 用作一个简单的开/关锁存器,或入口:在通过调用 countDown() 的线程打开入口前,所有调用 await 的线程都一直在入口处等待。

用 N 初始化的 CountDownLatch 可以使一个线程在 N 个线程完成某项操作之前一直等待,或者使其在某项操作完成 N 次之前一直等待。(API文档)

await会造成一个线程的阻塞,直到countdown到0;文档中说CountDownLatch 等待的是事件,也就是countdown到0,即之前的所有所需操作完成。

 

2、CyclicBarrier

一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。

 

多个线程共同工作,一个常用的比方是:大家一起出游,分别到达集合地点,共同去往目的地;到达目的地,分散活动,午餐时间集合;餐后分散,结束后集合回程。这种先分别执行,达到某一时间点,线程间相互等待,共同执行后,再分散,在集中的情形。

 

以上二者的区别:

CountDownLatch适用于有明确先后顺序的两组操作,前一组完成后开启后一组,开启功能完成(countdown到0),失去作用;await使线程等待,结束等待条件是countdown到0.

CyclicBarrier适用于多个线程之间需要相互等待,即线程的任务间有分-合-分-合的关系,只有个线程都达到条件后才能进行下一步操作(合),CyclicBarrier可以循环使用;await使线程等待,结束等待条件是等待的线程达到要求数目。

 

3、信号量Semaphore

Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。包含一个阻塞队列,信号量维护了一个许可集,在线程访问资源前,先要获取许可,许可通过acquire获取,若许可不可得则线程阻塞。release用于释放许可。流程:获取许可,同步获取资源,释放资源,释放许可。

 

4、Exchanger

用于线程间成对的交换数据,当一方数据准备好后调用exchange会等待另一方数据准备完成。

每个线程将条目上的某个方法呈现给 exchange 方法,与伙伴线程进行匹配,并且在返回时接收其伙伴的对象。(文档看不太明白)

exchanger参考http://hi.baidu.com/hxzon/item/d13c10deb656d2ef3cc2cb48



阻塞队列 BlockingQueue(文档)

线程安全,程序员不必考虑使用阻塞队列时的线程同步。

BlockingQueue 方法以四种形式出现,对于不能立即满足但可能在将来某一时刻可以满足的操作,这四种形式的处理方式不同:第一种是抛出一个异常,第二种是返回一个特殊值(null 或 false,具体取决于操作),第三种是在操作可以成功前,无限期地阻塞当前线程,第四种是在放弃前只在给定的最大时间限制内阻塞。下表中总结了这些方法:


抛出异常特殊值阻塞超时
插入add(e)offer(e)put(e)offer(e, time, unit)
移除remove()poll()take()poll(time, unit)
检查element()peek()不可用不可用

Java.util.concurrent包学习(三)同步集合

 

1、ArrayBlockingQueue  使用循环数组实现队列,使用一个可重入锁,及其上的两个条件Condition完成同步。

一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致操作受阻塞;试图从空队列中提取元素将导致类似阻塞

2、LinkedBlockingQueue 使用单链表实现队列,使用两个锁takelock、putlock及其条件实现同步,两个锁是的可以在链表头尾可以同时有线程在操作,一存一取,提高并发性。此外还有fullylock是两个锁的顺序组合,固定顺序可以避免死锁。参见参考博文

3、SynchronousQueue

一种无缓冲的等待队列,类似于无中介的直接交易,有点像原始社会中的生产者和消费者,生产者拿着产品去集市销售给产品的最终消费者,而消费者必须亲自去集市找到所要商品的直接生产者,如果一方没有找到合适的目标,那么对不起,大家都在集市等待。见参考博文


参考资料:锁机制:http://www.blogjava.net/xylz/archive/2010/07/08/325540.html


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值