AQS共享锁与独占锁对比

 

AQS框架图

上图是AQS框架大致的一些方法,还有一些没有全部的列出来。这里主要是让大家从这张图中,对AQS有一个总体的印象。总的来说AQS框架分为五层从对外暴露的API层到底层的数据层,当自定义同步器时候,只需要实现API的方法即可,不需要关注底层的具体实现逻辑。

共享模式和独占模式流程图对比

独占模式流程图

共享模式流程图

相同点

从流程图中,我们发现独占模式和共享模式,在竞争失败时,都会调用addWaiter方法,此方法都会把当前线程封装为Node节点添加到队列中。 

判断条件都是前驱节点是头节点的时候,设置当前节点为头节点,并且释放前驱节点。

不同点

共享模式比独占模式多做了一步操作,就是调用了doReleaseShared方法,去唤醒队列中所有共享模式的节点,让这些线程在去争夺共享资源,而独占式是没有这个操作的。

自定义锁 

AQS核心就是控制state值,通过这个state标志来控制线程争抢锁的。所以我们通过AQS实现自定义锁,只需要在AQS上层提供的API里面写自己的业务逻辑,控制state值即可。下面我们通过AQS来写一个重入锁的代码,所谓重入锁就是指在当前线程占有锁后,如果进来的线程和当前占有锁的线程相同,那么仍然可以获取锁.

public class ZLock {

    private static class Sync extends AbstractQueuedSynchronizer{
        @Override
        protected boolean tryAcquire(int arg) {
            //1 第一个线程进来,设置为宿主线程直接返回true
            //2 第二个线程进来,判断进来的线程和当前线程是否相同,
            //如果相同可以获取到锁。否则获取不到锁,返回false.
            int state=getState();
            Thread t=Thread.currentThread();
            if(state==0){
                if(compareAndSetState(0,arg)){
                    setExclusiveOwnerThread(t);
                    return true;
                }
            }
            else if(t==getExclusiveOwnerThread()){
                 setState(state+1);//记录同一个线程进来的次数
                 return true;
            }
            return false;
        }
        //锁的释放和加锁肯定是一一对应的,加锁了几次,就释放锁几次。
        // 直到记录的状态值更新为0
        @Override
        protected boolean tryRelease(int arg) {
            //释放锁时候,如果释放的线程不是当前的线程直接抛出异常
            if(Thread.currentThread()!=getExclusiveOwnerThread()){
                throw new RuntimeException();
            }
            int state=getState()-arg;
            setState(state);
            if(state==0){
                setExclusiveOwnerThread(null);
                return true;
            }
            return  false;
        }
    }
    private Sync sync=new Sync();

    public void lock(){
        sync.acquire(1);
    }
    public  void unLock(){
        sync.release(1);
    }
}
public class Test {
      static  int value=0;
      static ZLock myLock=new ZLock();
      public int getValue() {
          myLock.lock();
          try {
              Thread.sleep(10);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          value ++;
          myLock.unLock();
          return value;
      }

      public void a() {
          myLock.lock();
          System.out.println("a");
          b();
          myLock.unLock();
      }

      public void b() {
          myLock.lock();
          System.out.println("b");
          myLock.unLock();
      }


      public static void main(String[] args) throws InterruptedException {
          Test testMyLock = new Test();

          //检测是否会并发
          Runnable runnable = () -> {
              for (int i = 0; i<100; i++) {
                  System.out.println(Thread.currentThread().getId()+",值:" + testMyLock.getValue());
              }
          };

          new Thread(runnable).start();
          new Thread(runnable).start();
          new Thread(runnable).start();

          //检测重入锁
          Runnable runnable1 = () -> testMyLock.a();
          new Thread(runnable1).start();
      }
  }
  测试结果
  value值最终为300 说明锁生效
  输出 a b 说明同一个线程锁可以重入

更多内容并发内容可以订阅

  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值