Java线程与并发编程实践----额外的并发工具类

  一、并发集合

  java.util包下提供了很多的集合类,如ArrayList、TreeSet、HashMap,但是这些

  集合都是非线程安全的,并且对於单列集合的迭代器,采用的是快速失败机制,当正在迭代

  遍历的集合被其它线程修改时,便会抛出 java.util.ConcurrentModificationException。

  这显然对于多线程操作的集合是十分不方便的,但早Colections这个工具类中有方法可以返回

  线程安全的集合,然而这种集合对于高并发环境,性能十分低下。

  于是,java.util.concurrent包下提供了很多相关集合的类,即并发集合,这些集合

  具有并发性能和高扩展性,并且返回的是弱一致性的迭代器,即不再是快速失败机制的迭代器。

  大致描述如上,具体翻查jdk。下面单独研究使用并发集合完成生产者消费者的问题。

  使用BlockingQueue和ArrayBlockingQueue实现生产者消费者:

  ArrayBlockingQueue是一个由数组支的有界阻塞队列,当队列满载时,put()方法会阻塞,当

  队列为空时,take()方法阻塞,因此用这种队列可以很轻松的实现消费者、生产者。

  转到https://blog.51cto.com/12222886/1963884

  深入学习ConcurrentHashMap:

  重点了解此方法。

  ConcurrentHashMap是一个线程安全的集合,但是在多线程德操作之下它并不是线程安全

  的,例如如下代码:

  试想,当我们再判断完之后,还未put之前,有一条线程向map中put进一个键为something的值,

  然后我们再继续put,那么刚才的那个值是不是就被覆盖了?这就产生了安全问题。。为了保证

  安全我们应该这样做:

  以上可以解决安全问题,但是性能会被降低。。我们应该使用ConcurrentHashMap所提供的

  一个API,putIfabsent(K key,V value),它的含义是,假如键值不存在,便put进去,它是线程

  安全的,并且性能更高,相当于如下代码:

  二、原子变量

  和对象监听器关联的那些内置锁一直以来都有性能不佳的问题,后来出现了

  很多非阻塞算法,可大大提高性能和扩展性。

  java.util.concurrent.atomic提供了高效非阻塞算法。它支持单个变量可进行无

  锁及线程安全的操作。有如下原子类:

  原子变量用于实现计数器、序列生成器以及其它构造。在线程高争用的环境下,这些构造要求互斥

  而不影响性能。假如有如下代码:

  上述代码中volatile保证了可见性,synchronized保证了互斥性,在多线程环境下,上述代码没有

  问题,然而在高争用的环境中性能会很低。我们可以用原子变量代替上述代码:

  上述代码完全保证了可见性,互斥性以及操作的原子性,并且由于它实现了高争用下的非阻塞算法,

  因此它的性能相对来说高了很多。

  那么问题来了,为什么原子变量能够提高性能????

  Compare-and-swap(CAS机制)

  Compare-and-swap(CAS机制)是一个针对非抢占式微处理器的一条指定指令的宽泛术语,这条

  指令读取内存的位置,比较读到的值和期望的值,当读到值和期望值匹配时,就将新值存储到该内存

  位置,否则,什么也不发生。

  CAS支持原子的读-改-写序列,通常这样使用:

  (1)从地址A读取x

  (2)在x进行多步计算

  (3)使用CAS将A值从x变为y。在进行这些操作时,如果A值没有改变,CAS就成功了

  那CAS到底优越之处在哪呢?

  上面的代码使用synchronized,高争用环境下的监听锁会导致过多的上下文切换,这样会阻碍所有线程

  并且导致应用程序无法很好的扩展。而CAS机制不适用监听器来是操作原子化,而是在修改ID的值之前会

  进行判断,如果该值没发生过变化,就将新值赋值给该变量,如果发生变化了就什么也不做,而在这中间

  对值是否发生过变化的判断是利用CAS指令完成的。

  java.util.concurrent.locks.ReentrantLock就使用了CAS机制改善了性能,原子类也利用了CAS机制。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章