- 锁的种类
1 重入锁(ReentrantLock)
入这里指的是在某线程已经获取锁之后,该线程可以再次获取锁,进入同步代码块。
这里需要强调一下重入的概念中所指的线程是已经获得锁的的线程,这与线程安全不冲突
以下列出了synchronized与ReentrantLock的不同之处:
a ReentrantLock提供了显式加解锁操作。提供了lock(),unlock()方法进行加解锁的操作,而synchronized是隐式进行加锁与解锁操作(依赖于编译器将其编译为moniterenter与moniterexit)。
b 对锁的等待可以中断,在持有锁的线程长时间不释放锁时,等待锁的线程可以选择放弃等待,这样就避免了synchronized可能带来的死锁问题。ReentrantLock.tryLock()可以设置等待时间.
c ReentrantLock提供了公平锁与非公平锁,而synchronized的实现是非公平锁。
** 注意**
ReentrantLock相对于synchronized来说一般用于,加锁与解锁操作需要分离的使用场景,
例如加解锁不再一个函数里(synchronized无法用括号包围),相对来说ReentrantLock提供了更高的灵活性
,但是使用时一定不要忘了释放锁。
2 读写锁(ReentrantReadWriteLock)
a 在没有写操作线程获取写锁的情况下,所有读操作都可以获取读锁。
b 在有写线程获取写锁的情况下,读操作等待写线程释放锁后,才可以获取读锁
c 在有读线程获取读锁的情况下,写线程会等待所有读线程释放锁后,才可以获取写锁,并且与此同时,所有的读锁也不可获取。
实例:
public class ReentrantReadWriteLockHashMap {
private final Map<String, Object> hashMap = new HashMap<String, Object>();
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();
public final void put(String key, Object value){
//上写锁,不允许其他线程读也不允许写
writeLock.lock();
hashMap.put(key, value);
writeLock.unlock();
}
public final Object get( String key ){
//上读锁,其他线程只能读不能写
readLock.lock();
Object value = hashMap.get(key);
readLock.unlock();
return value;
}
}
3 volatile: 轻量级的线程操作可见方式
如果是多写场景,一定会出现线程安全问题
如果是一写多读的方式,则使用volatile非常合适,在实际中如果不能判断是否是一写多读的场景,一定要为加锁。
4 synchronized
关键词:synchronized 对象监控器 阻塞队列
参考
1 面试16解析-深挖锁