Java 并发包
并发包中除了提供高性能的线程安全的集合对象外,还提供了很多并发场景需要的原子操作类,例如AtomicInteger,另外还提供了一些用于避免并发时资源冲突的Lock及Condition类。
ConcurrentHashMap
线程安全的HashMap的实现。
维护的是一个Segment对象数组,segment继承ReentrantLock
方法 | 意义 |
---|---|
ConcurrentHashMap() | |
put(Object key,Object value) | ConcurrentHashMap基于concurrencyLevel划分出了多个segment来对key-velue进行存储,从而避免每次put操作都得锁住整个数组。在默认的情况下,最佳情况可以允许16个线程并发无阻塞的操作集合对象 |
remove(Object key) | |
get(Object) | |
containsKey(Object key) | |
keySet().iterator() |
CopyOnWriteArrayList
CopyOnWriteArrayList是一个线程安全,并且在读操作时无锁的ArrayList
在读多写少,且线程数很多的情况下,比较合适
- CopyOnWriteArrayList()
和ArrayList不同,创建一个大小为0的数组
- add()
首先使用ReentrantLock保证线程安全,另外每次都会创建一个新的Object数组,此数组的大小为当前数组大小加1,将之前数组中的内容复制到新的数组中,并将新增加的对象放到数组末尾,最后做引用切换将新创建的数组对象赋值给全局的数组对象
- remove(E)
首先通过ReentrantLock保证线程安全,然后删除,删除与ArrayList不同。
- get(int)
有可能读到脏数据
- iterator
CopyOnWriteArraySet
基于CopyOnWriteArrayList实现,唯一的不同是在add时调用的是CopyOnWriteArrayList的addIfAbsent方法
CopyOnWriteArraySet在add时每次都要进行数组遍历,因此性能会略低于CopyOnWriteArrayList.
ArrayBlockingQueue
一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。队列的头部 是在队列中存在时间最长的元素。队列的尾部 是在队列中存在时间最短的元素。新元素插入到队列的尾部,队列获取操作则是从队列头部开始获得元素。
这是一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致操作受阻塞;试图从空队列中提取元素将导致类似阻塞。
- ArrayBlockingQueue(int )
- offer(E,long,TimeUnit)
将指定的元素插入此队列的尾部,如果该队列已满,则在到达指定的等待时间之前等待可用的空间。
- poll(long,TimeUnit)
获取并移除此队列的头部,在指定的等待时间前等待可用的元素(如果有必要)。
- put(E)
将指定的元素插入此队列的尾部,如果该队列已满,则等待可用的空间。
- take()
获取并移除此队列的头部,在元素变得可用之前一直等待(如果有必要)。
AtomicInteger
支持原子操作的Integer类,
- AtomicInteger()
创建具有初始值 0 的新 AtomicInteger。
- AtomicInteger(int initialValue)
创建具有给定初始值的新 AtomicInteger。
- int addAndGet(int delta)
以原子方式将给定值与当前值相加。
- int decrementAndGet()
以原子方式将当前值减 1。
- int incrementAndGet()
以原子方式将当前值加 1。
- get()
获取当前值。
- set(int newValue)
设置为给定值。
Executors
创建线程池
- newFixedThreadPool(int)
- newCachedThreadPool()
- newSingleThreadPool()
FutureTask
可用于异步获取执行结果或取消执行任务的场景,通过传入Runnable或Callable的任务给FutureTask,直接调用其run方法或放入线程池执行,之后可在外部通过FutureTask的get异步获取执行结果。FutureTask可以确保即使调用了多次run方法,它都会执行一次Runnable或Callable任务,或者通过cancle取消FutureTask的执行。
方法 | 意义 |
---|---|
FutureTask(Callable callable) | 创建一个 FutureTask,一旦运行就执行给定的 Callable。 |
FutureTask(Runnable runnable, V result) | 创建一个 FutureTask,一旦运行就执行给定的 Runnable,并安排成功完成时 get 返回给定的结果 。 |
boolean cancel(boolean mayInterruptIfRunning) | 试图取消对此任务的执行。 |
protected void done() | 当此任务转换到状态 isDone(不管是正常地还是通过取消)时,调用受保护的方法。 |
V get() | 如有必要,等待计算完成,然后获取其结果。 |
V get(long timeout, TimeUnit unit) | 如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。 |
boolean isCancelled() | 如果在任务正常完成前将其取消,则返回 true。 |
boolean isDone() | 如果任务已完成,则返回 true。 |
void run() | 除非已将此 Future 取消,否则将其设置为其计算的结果。 |
protected boolean runAndReset() | 执行计算而不设置其结果,然后将此 Future 重置为初始状态,如果计算遇到异常或已取消,则该操作失败。 |
protected void set(V v) | 除非已经设置了此 Future 或已将其取消,否则将其结果设置为给定的值。 |
Semaphore
一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。
方法 | 意义 |
---|---|
Semaphore(int permits) | 创建具有给定的许可数和非公平的公平设置的 Semaphore。 |
Semaphore(int permits, boolean fair) | 创建具有给定的许可数和给定的公平设置的 Semaphore。 |
void acquire() | 从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。 |
void release() | 释放一个许可,将其返回给信号量。 |
public boolean tryAcquire() | 仅在调用时此信号量存在一个可用许可,才从信号量获取许可。(立即获取许可) |
CountDownLatch
用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。
方法 | 意义 |
---|---|
void await() | 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。 |
boolean await(long timeout, TimeUnit unit) | 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。 |
void countDown() | 递减锁存器的计数,如果计数到达零,则释放所有等待的线程。 |
long getCount() | 返回当前计数。 |
String toString() | 返回标识此锁存器及其状态的字符串。 |
CyclicBarrier
CyclicBarrier和CountDownLatch不同,CyclicBarrier是当await的数量到达了设定的数量后,才继续往下执行
该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
方法 | 意义 |
---|---|
CyclicBarrier(int parties) | 创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在启动 barrier 时执行预定义的操作。 |
int await() | 在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。 |
ReentrantLock
一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。
方法 | 意义 |
---|---|
ReentrantLock() | 创建一个 ReentrantLock 的实例。 |
void lock() | 获取锁。 |
void unlock() | 试图释放此锁。 |
Condition newCondition() | 返回用来与此 Lock 实例一起使用的 Condition 实例。 |
Condition
条件(也称为条件队列 或条件变量)为线程提供了一个含义,以便在某个状态条件现在可能为 true 的另一个线程通知它之前,一直挂起该线程(即让其“等待”)。
Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。
- void await()
当前线程在接到信号或被中断之前一直处于等待状态。
- void signal()
唤醒一个等待线程。
- void signalAll()
唤醒所有等待线程。
ReentrantReadWriteLock
读写锁,此锁最多支持 65535 个递归写入锁和 65535 个读取锁。试图超出这些限制将导致锁方法抛出 Error。
可以方便实现读者–写者问题
方法 | 意义 |
---|---|
ReentrantReadWriteLock.ReadLock readLock() | 返回用于读取操作的锁。 |
ReentrantReadWriteLock.WriteLock writeLock() | 返回用于写入操作的锁。 |
ReentrantReadWriteLock.ReadLock
- lock()
- unlock()
ReentrantReadWriteLock.WriteLock
- lock()
- unlock()
Exchager
可以在对中对元素进行配对和交换的线程的同步点。每个线程将条目上的某个方法呈现给 exchange 方法,与伙伴线程进行匹配,并且在返回时接收其伙伴的对象。Exchanger 可能被视为 SynchronousQueue 的双向形式。Exchanger 可能在应用程序(比如遗传算法和管道设计)中很有用。
Exchanger<V>
V - 可以交换的对象类型
方法 | 意义 |
---|---|
Exchanger() | 创建一个新的 Exchanger。 |
V exchange(V x) | 等待另一个线程到达此交换点(除非当前线程被中断),然后将给定的对象传送给该线程,并接收该线程的对象。 |
V exchange(V x, long timeout, TimeUnit unit) | 等待另一个线程到达此交换点(除非当前线程被中断,或者超出了指定的等待时间),然后将给定的对象传送给该线程,同时接收该线程的对象。 |
总结
- 并发框架下的集合类:
- ArrayBlockingQueue:一个有界阻塞队列,可以实现生产者–消费者问题
- CopyOnWriteArrayList:ArrayList 的一个线程安全的变体,其中所有可变操作(add、set 等等)都是通过对底层数组进行一次新的复制来实现的。
- CopyOnWriteArraySet:最适合于具有以下特征的应用程序:set 大小通常保持很小,只读操作远多于可变操作,需要在遍历期间防止线程间的冲突。
- LinkedBlockingQueue:链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。
- ConcurrentLinkedQueue:基于链接节点的无界线程安全队列
- ConcurrentHashMap:线程安全的HashMap实现
- 工具类
- CountDownLatch
- CyclicBarrier
cyclic:循环的,周期的
上述两个工具类都可以用来实现一个线程等待多个线程结束,从而确保几乎所有线程同时执行
- 原子操作
- AtomicInteger
- AtomicBoolean
- …
- 获取其他线程的返回值
- Callable
- FutureTask
- 资源竞争
- Semphore
- 互斥
- ReentrantLock
- Condition
- ReentrantReadWriteLock
- ReentrantReadWriteLock.WriteLock
- ReentrantReadWriteLock.ReadLock
版权声明:本文为博主原创文章,未经博主允许不得转载。