同步容器类
-
包括Vector和Hashtable,线程安全的实现方法是:将状态封装起来并对每个公有方法进行同步,使得每次只有一个线程能访问容器的状态
-
同步容器类都是线程安全的,但在某些情况下需要额外的客户端加锁保护复合操作(迭代、跳转、条件运算)
-
同步容器的迭代器没有考虑并发修改问题,当它们发现迭代过程中容器被修改了(迭代期间检查与容器关联的计数器是否被修改),会“及时失败”,抛出一个ConcurrentModificationException
-
单线程代码也可能抛出ConcurrentModificationException,当对象直接从容器中删除而不是通过Iterator.remove来删除时就会抛出这个异常
-
标准容器的toString/hashCode/equals方法会间接执行迭代操作,同理还有containsAll/removeAll/retainAll等方法,以及把容器作为参数的构造函数
并发容器
-
ConcurrentHashMap:使用了一个包含16个锁的数组,每个锁保护所有散列桶的1/16,提高伸缩性和并发性;已经实现了一些常见的复合原子操作如putIfAbsent…
-
CopyOnWriteArrayList、CopyOnWriteArraySet:代替同步List/Set,迭代期间不需要对容器进行加锁或复制,保留一个对底层基础数组(事实不可变对象)的引用,每次修改都会创建并重新发布一个新的容器副本
阻塞队列和生产者-消费者模式
-
BlockingQueue:简化生产者-消费者设计的实现过程,支持任意数量的生产者和消费者;
-
BlockingQueue有多种实现:
-
LinkedBlockingQueue和ArrayBlockingQueue是FIFO队列,比同步List有更好的并发性
-
PriorityBlockingQueue优先排序队列
-
SynchronousQueue没有存储空间,生产者直接交付工作给消费者,仅当有足够多的消费者,且总有一个消费者准备好获取交付工作时,才适合使用
-
-
串行线程封闭:线程间转移对象所有权,之前的所有者不会再访问它
-
Deque、BlockingDeque:对Queue和BlockingQueue进行扩展;工作密取:一个工作者要访问另一个工作者的队列,会从尾部获取,降低队列上的竞争程度
阻塞方法与中断方法
-
当方法抛出InterruptedException时,表示该方法是一个阻塞方法,如果它被中断,将努力提前结束中断状态
-
处理对中断的响应:
- 传递InterruptedException
- 恢复中断:
- 当代码是Runnable的一部分时,不能抛出InterruptedException(因为程序是实现了Runnable接口,然后在重写Runnable接口的run方法的时候,那么子类抛出的异常要小于等于父类的异常。而在Runnable中run方法是没有抛异常的)
- 必须捕获异常,通过调用当前线程上的interrupt方法中断状态,让调用栈中更高层的代码看到引发了一个中断(因为在捕获InterruptedException异常的时候自动将中断标志位置为了false,至少在捕获了InterruptedException异常之后,如果你什么也不想做,那么就将标志重新置为true)
public class TaskRunner implements Runnable {
private BlockingQueue<Task> queue;
public TaskRunner(BlockingQueue<Task> queue) {
this.queue = queue;
}
public void run() {
try {
while (true) {
Task task = queue.take(10, TimeUnit.SECONDS);
task.execute();
}
}
catch (InterruptedException e) {
// Restore the interrupted status
Thread.currentThread().interrupt();
}
}
}
同步工具类
-
闭锁:延迟线程的进度直到其到达终止状态,用于等待事件发生,一次性对象,一旦进入终止状态就不能被重置,CountDownLatch,await()
-
FutureTask:抽象的可生成结果的计算,也可以做闭锁;有三种状态:等待、正在运行、完成(结果可能是正常结束、取消或异常结束)
-
计数信号量Semaphore:控制同时访问某个特定资源的操作数量;二值信号量可以用来做互斥体(mutex)
-
栅栏:所有线程必须同时到达栅栏位置,用于等待其它线程,可以反复在栅栏位置汇集
- CyclicBarrier:barrier.await()
- Exchanger:两方栅栏,各方在栅栏位置交换数据