Java1.5 多线程新特性 Concurrent包分析

  1. 前言

在java 1.5之前,如果想实现多线程的一些操作,往往需要程序员自己来书写多线程的内容。这样会很痛苦,也很容易出现问题。但在自从1.5推出concurrent包后,多线程的书写将变得简单。我们有了一个非常好用的类库来实现多线程。

  1. Concurrent组成结构

该包的主要接口和类:

    Executor:具体Runnable的执行者。

    ExecutorService:一个线程池的管理者,有多种实现。比如:普通线程池,定时调度线程池。

    Futurn:与线程交互的接口。用于获取接口实现后的结果。

  1. 针对集合的优化

Concurrent包直接提供了一些针对多线程使用的集合优化,下面将对他们进行简要介绍。

  1. ConcurrentHashMap

Map的一个并发实现。在多线程情况下,他能够安全的运行,并有较高的效率。它支持并发读和写操作(默认情况下,可以支持16个的并发数量。在构造函数中可以修改)。

 

HashMap的实现是非线程安全的。在高并发情况下,使用get方法经常会发生死锁而且会导致cpu居高不下。所以在高并发状况下,不要使用HashMap。

 

Collection.synchronizedMap(new HashMap())相比, concurrentHashMap的效率会更高一些。

  1. BlockingQueue

BlockingQueue是一个接口,他实现了Queue。BlockingQueue是线程安全的,非常适合多个生产者和多个消费者线程之间传递数据。

 

抛出异常

返回布尔值

阻塞

超时

插入

Add(e)

Offer(e)

Put(e)

Offer(e,time,unit)

移除

Remove()

Poll()

Take()

Poll(time,unit)

检查

Element()

Peek()

  

形象地理解,BlockingQueue好比有很多格子的传输带系统,不过当你(生产者)调用put方法的时候,如果有空闲的格子那么放入物体后立刻返回,如果没有空闲格子那么一直处于等待状态。add方法意味着如果没有空闲格子系统就会报警,然后如果处理该报警则按照你的意愿。offer方法优先于add方法,它通过返回true flase来告诉你是否放入成功。offer超时方法,如果不空闲的情况下,尝试等待一段时间。

 

BlockingQueue有很多实现

ArrayBlockingQueueDelayQueueLinkedBlockingDequeLinkedBlockingQueuePriorityBlockingQueueSynchronousQueue

 

补充Dueue是个双向队列,可以当做堆栈来使用。BlockingQueueThreadPool中,作为任务队列来使用,用来保存没有立刻执行的工作任务对象。

  1. SynchronousQueue

SychronousQueueBlockingQueue的一个实现,它看起来是一个队列,但是其实没有容量,是特定条件下的一个精简实现。

 

做个比喻,SychronousQueue对象就像一个接力棒,现在有两个运动员交棒者和接棒者(线程)要做交接。在交接点,交棒者没有交出之前是不能松开的(一种等待状态),接棒者在接到棒之前是必须等待。换一句话说不管谁先到交接点,必须处于等待状态。

   

在生产者和消费者模型中。如果生产者向SychronousQueue进行put操作,直到有另外的消费者线程进行take操作时才能返回。对消费者也是一样,take操作会被阻塞,直到生产者put

   

在这种生产者-消费者模型下,生产者和消费者是进行手对手传递产品,在消费者消费一个产品之前,生产者必须处于等待状态。它给我们提供了在线程之间交换单一元素的极轻量级方法,并且具有阻塞语义。

   

提示:上面举例中有写局限性。其实生产者和消费者进程是可以任意数量的。MN。生产线程之间会对SychronousQueue进行争用,消费者也是一样。

   

SychronousQueue类似于其他语境中"会合通道" "连接"点问题。它非常适合于传递性设计,在这种设计中,在一个线程中运行的对象要将某些信息、事件或任务传递给在另一个线程中运行的对象,它就必须与该对象同步。

  1. Exchanger

SychronousQueue的双向实现。用来伙伴线程间交互对象。Exchanger 可能在比如遗传算法和管道设计中很有用。

 

形象地说,就是两个人在预定的地方交互物品,任何一方没到之前都处于等待状态。

 

  1. CopyOnWriteArrayList 和 CopyOnWriteArraySet

它们分别是List接口和Set接口的实现。正如类名所描述的那样,当数据结构发生变化的时候,会复制自身的内容,来保证一致性。大家都知道复制全部副本是非常昂贵的操作,看来这是一个非常不好的实现。事实上没有最好和最差的方案,只有最合适的方案。一般情况下,处理多线程同步问题,我们倾向使用同步的 ArrayList,但同步也有其成本。

     

那么在什么情况下使用CopyOnWriteArrayList 或者CopyOnWriteArraySet呢?

  1. 数据量小。
  2. 对数据结构的修改是偶然发生的,相对于读操作。

   

举例来说,如果我们实现观察者模式的话,作为监听器集合是非常合适的。

  1. TimeUnit

Concurrent包里面的时间单位。省去了时间换算。

原文地址:https://www.cnblogs.com/xitang/p/1982179.html