锁(想办法避免线程进入内核态的阻塞状态是分析和理解锁设计的关键)

锁(想办法避免线程进入内核态的阻塞状态是分析和理解锁设计的关键)
悲观锁

实例对象

  • 对象头(占用内存大小与虚拟机位长一致,32位JVM -> MarkWord是32位,64位JVM -> MarkWord是64位)
    • 类型指针:方法区地址,指向当前对象类型所在方法区中的类型信息,表明是哪个类的实例对象
    • MarkWord:hashcode值,锁相关信息,分代信息
      • 1.6对锁的优化
        • 无锁(检查对象头中是否存储了线程ID,若没有,CAS替换MarkWord将自己的线程ID存储在对象头中,无锁升级为偏向锁)
        • 偏向锁(对象头中存储着线程ID)
        • 轻量级锁(对象头中的MarkWord为指向线程虚拟机栈中锁记录的指针)
        • 重量级锁(用户态与核心态的切换,使线程进入内核态的阻塞状态)
  • 实例数据
  • 对齐填充
ReentrantLock的lock()方法
  1. 调用lock()方法
  2. 调用Sync的lock方法,Sync

Lock接口

  • lock方法(获取锁)
    
  • lockInterruptibly(获取锁)
    
  • tryLock(获取锁)
    
  • boolean tryLock(long time, TimeUnit unit)//尝试多久获取锁
    
  • unlock//释放锁
    
  • Condition newCondition()//新建一个绑定在当前Lock对象上的Condition对象
    

ReentrantLock是Lock接口的实现类

  • private final Sync sync;//成员变量,final修饰,一旦初始化,就不能修改引用了
    
  • Sync是抽象静态内部类继承自AQS

    abstract static class Sync extends AbstractQueuedSynchronizer {
    
  • NofairSync是静态内部类,非公平锁,不允许被继承

  • static final class NonfairSync extends Sync {
    
  • FairSync是静态内部类,公平锁,不允许被继承

  • static final class NonfairSync extends Sync {
    
  • ReentrantLock默认构造方法是非公平锁

  • public ReentrantLock() {
        sync = new NonfairSync();
    }
    
  • 但也可以通过有参构造方法实例化公平锁对象

  • public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
    
  • 调用lock方法获取锁,

    • 公平锁

      • 调用acquire方法(acquire方法是AQS的final方法,不允许被重写)

      • acquire方法调用tryAcquire方法,acquireQueued方法,addWaiter方法

      • public final void acquire(int arg) {
            if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                selfInterrupt();
        }
        
      • tryAcquire方法,尝试获取锁,公平锁对AQS的tryAcquire进行重写

      • protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
        
      • 当前对象没有线程占用时,判断是否有在当前线程前的线程(公平锁),没有就CAS,将当前独占线程更新为当前线程,当前对象有线程占用时,判断是不是当前线程(可重入锁),最大重入次数,int最大值,一直加就会变成负数

    • 非公平锁

      • 调用lock方法

      • 首先CAS获取锁,如果获取成功,将独占对象锁的线程更新为当前线程

      • CAS不成功,则调用acquire方法

      • final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
        
      • acquire是AQS中的final方法,不允许子类对方法进行重写

      • public final void acquire(int arg) {
            if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                selfInterrupt();
        }
        
      • addWaiter(Node.EXCLUSIVE)方法/为当前线程创建节点,加入等待队列

      • private Node addWaiter(Node mode) {
            Node node = new Node(Thread.currentThread(), mode);
            // Try the fast path of enq; backup to full enq on failure
            Node pred = tail;
            if (pred != null) {
                node.prev = pred;
                if (compareAndSetTail(pred, node)) {
                    pred.next = node;
                    return node;
                }
            }
            enq(node);
            return node;
        }
        
      • 通过当前线程和锁模式创建一个新节点

      • pred指针指向尾节点Tail

      • 如果尾节点不是空的,将新建节点的prev指向尾节点,通过CAS完成尾节点的设置

      • 如果尾节点是空的,初始化头结点,执行入队流程enq(node)

      • final boolean acquireQueued(final Node node, int arg) {
            boolean failed = true;
            try {
                boolean interrupted = false;
                for (;;) {
                    final Node p = node.predecessor();
                    if (p == head && tryAcquire(arg)) {
                        setHead(node);
                        p.next = null; // help GC
                        failed = false;
                        return interrupted;
                    }
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                        interrupted = true;
                }
            } finally {
                if (failed)
                    cancelAcquire(node);
            }
        }
        

        acquireQueued会把放入队列中的线程不断去获取锁,直到获取成功或者不再需要获取(中断)。

      • final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
        
      • 当前对象锁没有线程占用的时候,直接CAS,成功的话,将独占对象锁的线程更新为当前线程。如果对象锁已经被线程占用了,则判断是不是当前线程,(可重入锁)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值