一、同步队列
wait notifyall是一种低级的解决方式,更高的抽象级别使用同步队列来完成协作问题
BlockQueue 的子类
LinkedBlockingQueue
ArrayBlockingQueue
SynchronousQueue
1、ArrayBlockingQueue数据是放在一个数组中。LinkedBlockingQueue是放在一个Node节点中,构成一个链接。
2、ArrayBlockingQueue取元素和放元素都是同一个锁,而LinkedBlockingQueue有两个锁,一个放入锁,一个取得锁。分别对应放入元素
3、容量为0,无论何时 size方法总是返回0。put操作阻塞, 直到另外一个线程取走队列的元素。take操作阻塞,直到另外的线程put某个元素到队列中。
任何线程只能取得其他线程put进去的元素,而不会取到自己put进去的元素
二、新类库的构建
countdownlatch(并发的顺序控制--主线程控制子线程执行,主线程处理子线程执行结果)
CountDownLatch.await() //将await写成了wait
CountDownLatch.countDown()
主线程必须在启动其他线程后立即调用CountDownLatch.await()方法。这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务。
其他N 个线程必须引用闭锁对象,因为他们需要通知CountDownLatch对象,他们已经完成了各自的任务。这种通知机制是通过 CountDownLatch.countDown()方法来完成的;
每调用一次这个方法,在构造函数中初始化的count值就减1。所以当N个线程都调 用了这个方法,count的值等于0,然后主线程就能通过await()方法,恢复执行自己的任务。
CyclicBarrier(并发的周期性等待--比赛)
一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。
因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
DelayQueue(到期时才能从队列中取走)delayed+abstractqueue+blockingqueue+priorityqueue
是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中取走。这种队列是有序的,即队头对象的延迟到期时间最长。
注意:不能将null元素放置到这种队列中。
DelayQueue队列中保存的是实现了Delayed接口的实现类,里面必须实现getDelay(),用来判断是否到时间和compareTo()方法用来进行队列的排序
PriorityBlockingQueue(优先级队列)
compareto方法来比较两个任务的优先级,一般每个任务都传入一个不同的数值
管道和Exchanger<list<>>相似(只能两个之间,而且exchange后会阻塞,必须等待另一个exchange,相互交换数据)
PipedWriter PipedReader通过connected或者封装进构造方法相连
exchanger通过 data=exchanger.exchange(data)
Semaphore信号量
Semaphore(int permits, boolean fair)
通过acquire和release来实现
三、调优
synchronized和lock,lock的性能要优于synchronized,原子类是最快的,但并不普适
CopyOnWriterList
CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。
这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。
Vector和HashTable使用synchronized方法,线程安全的,还有collections类提供的静态装饰方法实现加锁
(HashMap 线程不安全,迭代器是fail-fast;HashTable线程安全的,但一次仅有一个线程能够更改Hashtable,效率比较低,迭代器非fast-fail,可以进行元素增删;CurrentHashMap线程安全,是对hashtable的一种替换)
解决hashmap的不安全的问题,包括arraylist,可以使用Collections.synchronizeMap(hashMap);
concurrenthashmap使用锁分段技术segment来保证线程安全,首先将数据分成一段一段存储,给每一段加一把锁,一个线程占用锁访问一个段数据时,其它段的数据可以被其他线程访问。
乐观锁与悲观锁
乐观锁:假设不会发生冲突,仅在数据提交的时候采取检查。常用的方法为版本号和时间戳
悲观锁:整个数据处理过程中加锁操作