Concurrency: New Library Components (2)

5. ScheduledExecutor

  ScheduledThreadPoolExecutor提供了多种执行任务的方式,schedule()用于延时执行一次任务,scheduleAtFixedRate()scheduleWithFixedDelay()用于定时重复执行,它们具有类似的签名:

二者都会在initialDelay后初次执行command,之后:

  • scheduleAtFixedRate()会每在command开始执行后的period时间之后,再次执行command
  • scheduleWithFixedDelay()会每在command执行完毕后的delay时间之后,再次执行执行command

  一个例子如下:

6. Semaphore

  区别于concurrent.locks锁和内置的synchronized锁同一时间只允许同一个任务访问共享资源,计数信号量(Counting Semaphore)允许n个任务同时访问共享资源。

  下面的例子采用了对象池(Object Pool)的概念,对象池管理有限个对象,允许对象被提取出去使用,使用完后对象需要被归还会对象池。

构造器通过classObject.newInstance()初始化固定数量个对象,通过checkOut()checkIn()提取和归还对象池中的对象。checkOut()首先通过available.acquire()获取信号量,如果能够成功获取,意味着对象池中还有剩余的对象,则由getItem()从对象池中取出一个对象。checkIn()首先调用releaseItem()releaseItem()会判断归还的对象是否合法,成功归还后,通过available.release()释放信号量。

  为了演示Pool<T>的用法,首先创建一个构造起来非常耗时的类:

  然后使用Pool<Fat>来存储固定数量的Fat

Fat对象池中有SIZE个对象,首先由SIZECheckoutTask从对象池中checkOut()checkIn()对象。之后在main()checkOut()全部对象,当在blocked中尝试checkOut()时,对象池已空,会发生阻塞。最后main()checkIn()全部对象,重复checkIn()没有作用。

7. Exchanger

  Exchanger用于在两个任务间交换对象,通常用于在一个任务中创建对象,并把它交换到另一个任务中进行消耗。

这里交换的对象是List<Fat>ExchangerProducer生成List<Fat>ExchangerConsumer消耗List<Fat>,二者通过同一个Exchanger<List<Fat>> xc联系起来。ExchangerConsumer在调用exchanger.exchange()时,会产生阻塞;直到ExchangerProducer填充完List<Fat>,并调用exchanger.exchange()后,ExchangerProducerExchangerConsumer持有的List<Fat>holder)被交换,ExchangerConsumer得到了填充后的列表,ExchangerProducer得到了空的列表。Exchanger使得资源的生产和消耗得以同时进行。