前言
synchronized
synchronized
是Java的关键字
,当它用来修饰一个方法或一个代码块时,能够保证在同一时刻最多只有一个线程执行该代码。因为当调用synchronized
修饰的代码时,并不需要显示的加锁和解锁的过程,所以称之为隐式锁
。
Lock
Lock
是一个接口
,提供了无条件的
、可轮询的
、定时的
、可中断
的锁获取操作,所有的加锁和解锁操作方法都是显示
的,因而称为显示锁
。
Lock接口和synchronized的比较
- synchronized 代码简洁
- Lock获取锁可以被中断,超时获取锁,尝试获取锁,读多写少用读写锁
- 二者都是可重入锁
ReentrantLock
ReentrantLock 可重入锁 构造函数可以指定是否是公平锁,默认是非公平锁
可重入锁:
一个同步方法可以调用另外一个同步方法,一个线程已经拥有某个对象的锁,再次申请的时候仍然会得到该对象的锁。
不可重入锁:
即当前线程获取这把锁后,要想再拿到这把锁,必须释放当前持有的锁,这时我们称这个锁是不可重入的。
公平锁:
如果在时间上,先对锁进行获取的请求,一定先被满足,这个锁就是公平的
非公平锁:
上来就直接尝试占有锁,如果尝试失败,就再采用类似公平锁那种方式。非公平锁效率要高
使用示例:
private final ReentrantLock lock = new ReentrantLock();
public void doSomething(){
lock.lock();//获得锁
try{
//处理业务
}finally{
lock.unlock();//最后释放锁
}
}
注意:在使用显示锁时,一定要有释放锁的操作。
ReadWriteLock接口以及实现类ReentrantReadWriteLock
ReadWriteLock (读写锁) 是一个接口,提供了readLock和writeLock两种锁的操作,也就是说一个资源能够被多个读线程访问,或者被一个写线程访问,但是不能同时存在读写线程。也就是说读写锁应用的场景是一个资源被大量读取操作,而只有少量的写操作。我们先看其源码:
public interface ReadWriteLock {
Lock readLock();
Lock writeLock();
}
使用示例:
private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private Lock readLock = rwl.readLock();//读锁
private Lock writeLock = rwl.writeLock(); //写锁
public int read(){
readLock.lock();
try{
//读操作
}finally{
readLock.unlock();
}
}
public void write(){
writeLock.lock();
try{
//写操作
}finally{
writeLock.unlock();
}
}
Condition
显示锁中的条件接口Condition
,包含如等待和唤醒之类的方法,Condition
对象是由Lock
对象(调用Lock对象的newCondition()方法)创建出来的,换句话说,Condition是依赖Lock对象的。在显示锁中,唤醒是用signal
,而最好不用signalAll
,因为signal
可以精准唤醒指定的线程,而在隐士锁中用notifyAll
,而不用notify
,因为notify
不能精准唤醒,可能导致死锁。signalAll
只能唤醒指定Condition
上的等待的线程,其他线程也不能被唤醒,和notifyAll
不同。