Concurrent下的线程安全集合
2016-08-30 00:42
363 查看
转自:http://www.cnblogs.com/ijavanese/p/3778688.html
1.ArrayBlockingQueue
ArrayBlockingQueue是由数组支持的线程安全的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。这是一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致操作受阻塞;试图从空队列中提取元素将导致类似阻塞。此类支持对等待的生产者线程和消费者线程进行排序的可选公平策略。默认情况下,不保证是这种排序。然而,通过将公平性 (fairness) 设置为 true 而构造的队列允许按照 FIFO 顺序访问线程。公平性通常会降低吞吐量,但也减少了可变性和避免了“不平衡性”。
复制代码
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
复制代码
从改造方法可以看出,ArrayBlockingQueue的实现机制是ReentrantLock和Condition来实现的。
2、LinkedBlockingDeque
LinkedBlockingDeque是用双向链表实现的,需要说明的是LinkedList也已经加入了Deque的一部分。
/* Maximum number of items in the deque /
private final int capacity;
复制代码
/**
* Creates a {@code LinkedBlockingDeque} with a capacity of
* {@link Integer#MAX_VALUE}.
*/
public LinkedBlockingDeque() {
this(Integer.MAX_VALUE);
}
复制代码
public LinkedBlockingDeque(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
}
要想支持阻塞功能,队列的容量一定是固定的,否则无法在入队的时候挂起线程。也就是capacity是final类型的。
既然是双向链表,每一个结点就需要前后两个引用,这样才能将所有元素串联起来,支持双向遍历。也即需要prev/next两个引用。
双向链表需要头尾同时操作,所以需要first/last两个节点,当然可以参考LinkedList那样采用一个节点的双向来完成,那样实现起来就稍微麻烦点。
既然要支持阻塞功能,就需要锁和条件变量来挂起线程。这里使用一个锁两个条件变量来完成此功能。
3、LinkedBlockingQueue
LinkedBlockingQueue是一个基于已链接节点的、范围任意的blocking queue的实现,也是线程安全的。按 FIFO(先进先出)排序元素。队列的头部 是在队列中时间最长的元素。队列的尾部 是在队列中时间最短的元素。
复制代码
/**
* Creates a {@code LinkedBlockingQueue} with a capacity of
* {@link Integer#MAX_VALUE}.
*/
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
复制代码
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node(null);
}
可选的容量范围构造方法参数作为防止队列过度扩展的一种方法。如果未指定容量,则它等于 Integer.MAX_VALUE。除非插入节点会使队列超出容量,否则每次插入后会动态地创建链接节点。
此外它还不接受null值:
复制代码
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
// Note: convention in all put/take/etc is to preset local var
// holding count negative to indicate failure unless set.
int c = -1;
Node node = new Node(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
复制代码
4、PriorityBlockingQueue
PriorityBlockingQueue是一个无界的线程安全的阻塞队列,它使用与PriorityQueue相同的顺序规则,并且提供了阻塞检索的操作。
复制代码
public PriorityBlockingQueue(int initialCapacity,
Comparator
1.ArrayBlockingQueue
ArrayBlockingQueue是由数组支持的线程安全的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。这是一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致操作受阻塞;试图从空队列中提取元素将导致类似阻塞。此类支持对等待的生产者线程和消费者线程进行排序的可选公平策略。默认情况下,不保证是这种排序。然而,通过将公平性 (fairness) 设置为 true 而构造的队列允许按照 FIFO 顺序访问线程。公平性通常会降低吞吐量,但也减少了可变性和避免了“不平衡性”。
复制代码
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
复制代码
从改造方法可以看出,ArrayBlockingQueue的实现机制是ReentrantLock和Condition来实现的。
2、LinkedBlockingDeque
LinkedBlockingDeque是用双向链表实现的,需要说明的是LinkedList也已经加入了Deque的一部分。
/* Maximum number of items in the deque /
private final int capacity;
复制代码
/**
* Creates a {@code LinkedBlockingDeque} with a capacity of
* {@link Integer#MAX_VALUE}.
*/
public LinkedBlockingDeque() {
this(Integer.MAX_VALUE);
}
复制代码
public LinkedBlockingDeque(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
}
要想支持阻塞功能,队列的容量一定是固定的,否则无法在入队的时候挂起线程。也就是capacity是final类型的。
既然是双向链表,每一个结点就需要前后两个引用,这样才能将所有元素串联起来,支持双向遍历。也即需要prev/next两个引用。
双向链表需要头尾同时操作,所以需要first/last两个节点,当然可以参考LinkedList那样采用一个节点的双向来完成,那样实现起来就稍微麻烦点。
既然要支持阻塞功能,就需要锁和条件变量来挂起线程。这里使用一个锁两个条件变量来完成此功能。
3、LinkedBlockingQueue
LinkedBlockingQueue是一个基于已链接节点的、范围任意的blocking queue的实现,也是线程安全的。按 FIFO(先进先出)排序元素。队列的头部 是在队列中时间最长的元素。队列的尾部 是在队列中时间最短的元素。
复制代码
/**
* Creates a {@code LinkedBlockingQueue} with a capacity of
* {@link Integer#MAX_VALUE}.
*/
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
复制代码
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node(null);
}
可选的容量范围构造方法参数作为防止队列过度扩展的一种方法。如果未指定容量,则它等于 Integer.MAX_VALUE。除非插入节点会使队列超出容量,否则每次插入后会动态地创建链接节点。
此外它还不接受null值:
复制代码
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
// Note: convention in all put/take/etc is to preset local var
// holding count negative to indicate failure unless set.
int c = -1;
Node node = new Node(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
复制代码
4、PriorityBlockingQueue
PriorityBlockingQueue是一个无界的线程安全的阻塞队列,它使用与PriorityQueue相同的顺序规则,并且提供了阻塞检索的操作。
public PriorityBlockingQueue(int initialCapacity) { this(initialCapacity, null); }
复制代码
public PriorityBlockingQueue(int initialCapacity,
Comparator
相关文章推荐
- .NET中保证线程安全的高级方法Interlocked类使用介绍
- Java线程安全中的单例模式
- 深入线程安全容器的实现方法
- PHP 线程安全与非线程安全版本的区别深入解析
- 深入理解线程安全与Singleton
- 谈谈java的concurrent用法
- java多线程之线程安全的单例模式
- Java BlockingQueue
- 多线程问题及处理方法【转】
- 编程语言当前并发思路比较
- JDK高性能编程之多线程
- JAVA并发编程
- LockSupport并发等待基本模型
- Java之线程安全的简单理解
- 图学java基础篇之并发
- iOS中保证线程安全的几种方式与性能对比
- android的线程安全
- ConcurrentHashMap并不是绝对线程安全的
- Springmvc并发访问的线程安全性问题
- Servlet和 Struts线程安全问题