Java并发编程指南(六):并发集合

1. 非阻塞线程安全的列表 ConcurrentLinkedDeque

并发列表允许不同的线程在同一时刻对列表的元素进行添加add()或删除pollFirst(),pollLast(),而不会产生任何数据不一致(问题)。

  • add(), addFirst(), addLast(): 这些方法允许在列表的头部或者尾部插入一个元素。如果没有可用空间将会抛出异常。
  • poll(), pollFirst()和pollLast():这些方法将分别返回列表的第一个和最后一个元素。并且从列表删除返回的元素。如果列表为空,返回null.

  • get(), getFirst()getLast():这些方法将分别返回列表的第一个和最后一个元素。它们不会从列表删除返回的元素。如果列表为空,这些方法将抛出NoSuchElementExcpetion异常。
  • peek()、peekFirst()peekLast():这些方法将分别返回列表的第一个和最后一个元素。它们不会从列表删除返回的元素。如果列表为空,这些方法将返回null值。
  • remove()、removeFirst()、 removeLast():这些方法将分别返回列表的第一个和最后一个元素。它们将从列表删除返回的元素。如果列表为空,这些方法将抛出NoSuchElementExcpetion异常。

2, 阻塞线程安全的列表 LinkedBlockingDeque

  • put()方法向列表中添加元素。如果列表已满,这个方法阻塞线程的执行,直到列表有可用空间。
  • take()方法从列表中获取字符串,如果列表为空,这个方法将阻塞线程的执行,直到列表中有元素。
  • takeFirst() 和takeLast():这些方法分别返回列表的第一个和最后一个元素。它们从列表删除返回的元素。如果列表为空,这些方法将阻塞线程,直到列表有元素。
  • getFirst() 和getLast():这些方法分别返回列表的第一个和最后一个元素。它们不会从列表删除返回的元素。如果列表为空,这些方法将抛出NoSuchElementExcpetion异常。
  • peek()、peekFirst(),和peekLast():这些方法分别返回列表的第一个和最后一个元素。它们不会从列表删除返回的元素。如果列表为空,这些方法将返回null值。
  • poll()、pollFirst()和 pollLast():这些方法分别返回列表的第一个和最后一个元素。它们从列表删除返回的元素。如果列表为空,这些方法将返回null值。
  • add()、 addFirst()、addLast():这些方法分别在第一个位置和最后一个位置上添加元素。如果列表已满(你已使用固定大小创建它),这些方法将抛出IllegalStateException异常。


3,用优先级对使用阻塞线程安全的列表排序 PriorityBlockingQueue



4, 使用线程安全的、带有延迟元素的列表 DelayedQueue

DelayedQueue类是Java API提供的一种有趣的数据结构,并且你可以用在并发应用程序中。在这个类中,你可以存储带有激活日期的元素。方法返回或抽取队列的元素将忽略未到期的数据元素。它们对这些方法来说是看不见的。
为了获取这种行为,你想要存储到DelayedQueue类中的元素必须实现Delayed接口。这个接口允许你处理延迟对象,所以你将实现存储在DelayedQueue对象的激活日期,这个激活时期将作为对象的剩余时间,直到激活日期到来。这个接口强制实现以下两种方法:
  • compareTo(Delayed o):Delayed接口继承Comparable接口。
  • getDelay(TimeUnit unit):该方法返回与此对象相关的剩余延迟时间,以给定的时间单位表示。返回值小于等于0时表示元素到期。

5, 创建并发随机数 ThreadLocalRandom

Java并发API提供指定的类在并发应用程序中生成伪随机。它是ThreadLocalRandom类,这是Java 7版本中的新类。它使用线程局部变量。每个线程希望以不同的生成器生成随机数,但它们是来自相同类的管理,这对程序员是透明的。在这种机制下,你将获得比使用共享的Random对象为所有线程生成随机数更好的性能。
ThreadLocalRandom类同样提供方法来生成long、float 和 double类型的数以及 Boolean值。这些方法允许你传入一个数值作为参数,然后生成0到这个数值之间的随机数。还有允许你传入两个参数的其他方法,然后生成在这两个参数数值之间的随机数。


6,使用原子变量,原子数组

AtomicInteger, AtomicLong, AtomicBoolean,AtomicIntegerArray, AtomicLongArray等

当你实现一个多个线程共享一个或者多个对象的并发应用时,你就要使用像锁或者同步关键词(例如synchronized)来对他们的属性的访问进行保护,来避免并发造成的数据不一致的错误。
但是这些机制会有以下一些缺点:

  • 死锁(dead lock):例如:当一个线程等待一个锁的时候,会被阻塞,而这个锁被其他线程占用并且永不释放。这种情况就是死锁,程序在这种情况下永远都不会往下执行。
即使只有一个线程在访问共享对象,它也要执行必要的获取锁和释放锁的代码。

CAS(compare-and-swap)操作为并发操作对象的提供更好的性能,CAS操作通过以下3个步骤来实现对变量值得修改:
  • CPU获取当前内存中的变量的值,就是变量的旧值。
  • CPU用一个新的临时变量(temporal variable)保存改变后的新值
  • 如果当前内存中的值等于变量的旧值,则将新值赋值到当前变量;否则不进行任何操作。因为可能有其他线程修改了变量的值使得旧的值已经和内存中的值不一致了。
对于这个机制,你不需要使用任何同步机制,这样你就避免了 deadlocks,也获得了更好的性能。这种机制能保证多个并发线程对一个共享变量操作做到最终一致。

Java 在原子类中实现了CAS机制。这些类提供了compareAndSet() 方法;这个方法是CAS操作的实现和其他方法的基础。

Java 中还引入了原子Array,用来实现Integer类型和Long类型数组的操作。



猜你喜欢

转载自blog.csdn.net/sunjin9418/article/details/79564920