目录
四、ReentrantLock 和 synchronize异同
一、CLH同步队列
参考:https://blog.csdn.net/weixin_40391011/article/details/104701988
二、手动模拟AQS锁
state可以理解为信号量
public class MyLock implements Lock {
private Helper helper=new Helper();
private class Helper extends AbstractQueuedSynchronizer{
//获取锁
@Override
protected boolean tryAcquire(int arg) {
int state=getState();
if(state==0){
//利用CAS原理修改state
if(compareAndSetState(0,arg)){
//设置当前线程占有资源
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
//else if解决可重入性问题
}else if(getExclusiveOwnerThread()==Thread.currentThread()){
setState(getState()+arg);
return true;
}
return false;
}
//释放锁
@Override
protected boolean tryRelease(int arg) {
int state=getState()-arg;
boolean flag=false;
//判断释放后是否为0
if(state==0){
setExclusiveOwnerThread(null);
setState(state);
return true;
}
setState(state);//存在线程安全吗?重入性的问题,当前已经独占了资源()state
return false;
}
public Condition newConditionObjecct(){
return new ConditionObject();
}
}
@Override
public void lock() {
helper.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
helper.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return helper.tryAcquire(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return helper.tryAcquireNanos(1,unit.toNanos(time));
}
@Override
public void unlock() {
helper.release(1);
}
@Override
public Condition newCondition() {
return helper.newConditionObjecct();
}
}
三、可重入锁ReentrantLock
同一个锁对同一资源进行占有的时候,直接分配给这个线程
ReentrantLock是独占式可重入锁,默认是非公平锁,可以具体设置为公平锁还是非公平锁。
实例:
import java.util.concurrent.locks.ReentrantLock;
public class Demo03 {
private ReentrantLock lock=new ReentrantLock();
private int m=0;
public void a(){
lock.lock();
System.out.println("a");
b();
lock.unlock();
}
public void b(){
lock.lock();
System.out.println("b");
lock.unlock();
}
public static void main(String[] args) {
Demo03 demo=new Demo03();
new Thread(()->{
demo.a();
}).start();
}
}
注意点:
锁降级:由写锁到读锁。在释放写锁(write.unlock)之前需要加上读锁(read.lock())。
锁升级:由读锁到写锁。但是在ReentrantReadWriteLock中不支持。
ReentrantReadWriteLock:锁是一个读写分离的锁,这种锁主要用于读多写少的业务场景,口诀就是:读读共享、写写互斥、读写互斥。
四、ReentrantLock 和 synchronize异同
synchronize 和Lock:
1、synchronize 系java 内置关键字;而Lock 是一个类
2、synchronize 可以作用于变量、方法、代码块;而Lock 是显式地指定开始和结束位置
3、synchronize 不需要手动解锁,当线程抛出异常的时候,会自动释放锁;而Lock则需要手动释放,所以lock.unlock()需要放在finally 中去执行
4、性能方面,如果竞争不激烈的时候,synchronize 和Lock 的性能差不多,如果竞争激烈的时候,Lock 的效率会比synchronize 高
5、Lock 可以知道是否已经获得锁,synchronize 不能知道。Lock 扩展了一些其他功能如让等待的锁中断、知道是否获得锁等功能;Lock 可以提高效率。
6、synchronize 是悲观锁的实现,而Lock 则是乐观锁的实现,采用的CAS 的尝试机制
synchronize 和 ReentrantLock:
ReentrantLock的作用和synchronize是一样的,都是实现锁的功能,但是ReentrantLock需要手写代码对锁进行获取和释放(一定要在finally里面释放),要不然就永远死锁了,ReentrantLock也可以用来做线程之间的挂起和通知,synchronize一般是使用object的wait和notify来实现,ReentrantLock使用Condition来实现线程之间的通信。
除开上面和Lock 的区别,还有一下的一些区别:
1、ReenTrantLock 可以中断锁的等待,提供了一些高级功能;
2、多个线程在等待的时候,可以提供公平的锁;默认的是非公平锁,性能会比公平锁好一些;
3、ReenTrantLock 可以绑定多个锁条件