多线程之线程安全的几种方法
synchronized:
同步代码块
synchronized (临界资源对象){//对临界资源对象加锁
//代码(原子操作)
}
同步代码块锁的是对象,如果两个或两个以上的线程想要访问同一个对象的时候,必须要排队访问
同步方法
使用synchronize修饰的方法,称之为同步方法,
如果是实例方法,锁定的是调用此方法的对象,也就是this
如果是静态方法,锁定的是当前的类,相当于类名.class
public synchronized void add(){
}
Lock同步锁
lock锁是一个抽象类,我们需要使用它的子实现类
常用实现类:ReentrantLock ,
ReentrantReadWriteLock.ReadLock ,
ReentrantReadWriteLock.WriteLock
使用lock锁
- 创建一个lock锁对象
Lock lock = new ReentrantLock();
//获取锁:
lock.lock();
//释放锁
locl.unlock();
注: 最好要把释放锁的操作写在finally{}块里,以保证锁的释放
volatile
被volatile修饰的属性具有可见性,即如果有某一线程修改了此属性,他将立刻被所有线程可见
线程安全集合
CopyOnWriteArrayList
线程安全的ArrayList集合,加强版的读写分离,
读的时候没有锁,写的时候有锁
写的时候是先copy一个集合副本,再添加新元素,最后替换掉原来的集合引用
缺点:浪费空间
CopyOnWriteArraySet
线程安全的set集合.底层使用的是CopyOnWriteArrayList 实现
唯一不同在于,使用addIfAbsent()添加元素,会遍历数组,如果存在元素,则不添加(使用equals()判断)
跟set集合有点不一样,这个集合是有序的
ConcurrentLinedQueue(非阻塞队列)
线程安全可高效读写的队列,高并发下性能最好的队列,
无锁,采用CAS比较交换算法,修改的方法包括三个值VEN,
V要更新的变量,E,预期值,N新值
只有当V= E时,V= N,否则取消操作
BlockingQueue(阻塞队列):接口
可用于解决生产者消费者的问题
Queue的子接口,阻塞的队列,增加了两个无期限等待的方法
- put(E e): 将指定元素插入队列,如果没有可用空间,则无期限等待
- take():获取并移除队列的头部元素,如果没有可用元素,则等待
ArrayBlockingQueue
数组结构实现,手动确定上限
LinkedBlockingQueue
链表结构实现,默认上限Integer.MAX.VALUE
concurrentHashMap
采用的是分段锁的设计方式,初始容量分成了16段(Segment)java1.7
不对整个map加锁,是对每个段加锁
当多个对象同时存入一个段(segment)时,这个时候才需要互斥
java1.7之后也是采用CAS算法来实现的