本文共 2189 字,大约阅读时间需要 7 分钟。
包括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时,表示该方法是一个阻塞方法,如果它被中断,将努力提前结束中断状态
处理对中断的响应:
public class TaskRunner implements Runnable { private BlockingQueuequeue; public TaskRunner(BlockingQueue 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)
栅栏:所有线程必须同时到达栅栏位置,用于等待其它线程,可以反复在栅栏位置汇集
转载地址:http://elkvb.baihongyu.com/