Lock&Condition

锁类继承层次

Lock
void lock()
void lockInterruptibly()
boolean tryLock()
boolean tryLock(long time, TimeUnit unit)
void unlock()
Condition newCondition()
ReentrantLock
AbstractOwnableSynchronizer
private transient Thread exclusiveOwnerThread
AbstractQueuedSynchronizer
private volatile int state
private transient volatile Node head
private transient volatile Node tail
private Node addWaiter(Node mode)
final boolean acquireQueued(final Node node, int arg)
private final boolean parkAndCheckInterrupt()
public final boolean release(int arg)
NonFairSync
public final void acquire(int arg)
protected final boolean tryAcquire(int acquires)
protected final boolean tryRelease(int releases)
FairSync
public final void acquire(int arg)
protected final boolean tryAcquire(int acquires)
protected final boolean tryRelease(int releases)
Sync
Node
volatile Node prev
volatile Node next
volatile Thread thread

锁工具类LockSupport

public class LockSupport {

    private static final Unsafe UNSAFE;
    
    public static void park() {
        UNSAFE.park(false, 0L);
    }
    
    public static void unpark(Thread var0) {
        if (var0 != null) {
            UNSAFE.unpark(var0);
        }

    }
}

线程中调用park()会阻塞当前线程,在其它线程中调用unpark(thread),可精准唤醒指定的线程

参数作用

AbstractOwnableSynchronizer

Thread exclusiveOwnerThread : 表示当前持有锁的线程

AbstractQueuedSynchronizer

volatile int state :当前锁的状态,cas保证线程安全
transient volatile Node head:阻塞队列头
transient volatile Node tail:阻塞队列尾
Node addWaiter(Node mode):将当前线程构建成node加入阻塞队列
boolean acquireQueued(final Node node, int arg):实现线程阻塞逻辑调用
boolean parkAndCheckInterrupt():线程的自我阻塞
boolean release(int arg) :解锁

NonFairSync&FairSync

void acquire(int arg):获取锁
final boolean tryAcquire(int acquires):尝试获取锁

boolean tryRelease(int releases) :尝试解锁

加锁流程图

true
false
ReentrantLock.lock
Sync.acquire
Sync.tryAcquire
return
AbstractQueuedSynchronizer.addWaiter
AbstractQueuedSynchronizer.parkAndCheckInterrupt
acquire(int arg) 与 tryAcquire(int arg)
public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
}

当 acquireQueued(…)返回 true 时,会调用 selfInterrupt(),自己给自己发送中断信号,也就是自
己把自己的中断标志位设为true。之所以要这么做,是因为自己在阻塞期间,收到其他线程中断信号没
有及时响应,现在要进行补偿。这样一来,如果该线程在lock代码块内部有调用sleep()之类的阻塞方
法,就可以抛出异常,响应该中断信号。

tryAcquire(int arg)

非公平锁实现

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
        
        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;
        }        

公平锁实现

    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;
        }

由代码可以看出,公平锁获取锁前会判断(hasQueuedPredecessors())队列中是否有任务线程,没有才会去竞争锁状态(state)。而非公平锁则是直接去竞争锁状态(state)

阻塞逻辑acquireQueued(final Node node, int arg)
    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;
                }
                //没有则进入线程阻塞parkAndCheckInterrupt()
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

进入队列中,都是公平锁了。会进行如下操作
1、判断是不是头节点,是的话回去尝试竞争锁状态
2、竞争到锁以后直接返回
3、没有则进入线程阻塞parkAndCheckInterrupt()
4、阻塞线程唤醒后,重复1234操作

parkAndCheckInterrupt()
    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

解锁流程图

true
false
ReentrantLock.unlock
Sync.release
Sync.tryRelease
LockSupport.unpark
return false
return true
release(int arg)
    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
            //唤醒阻塞的头节点线程
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

tryRelease(int releases)
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
            \\持锁线程不是当前线程,直接扔异常
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                //持锁线程清空
                setExclusiveOwnerThread(null);
            }
            //状态修改
            setState(c);
            return free;
        }

修改状态时没有用到cas,因为此时处理是单线程的。状态等于0时才清空持锁线程,为了处理锁重入的情况。

unparkSuccessor(Node node)
    private void unparkSuccessor(Node node) {
       
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);

        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }

可中断锁的实现lockInterruptibly()

    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
    
    public final void acquireInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())//中断标识检测
            throw new InterruptedException();
        if (!tryAcquire(arg))
            doAcquireInterruptibly(arg);
    }
    
    private void doAcquireInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    //关键点
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
    
    

主要关键点在doAcquireInterruptibly方法中线程阻塞后判断中断标识,如果标识为true,则抛出InterruptedException。以及acquireInterruptibly方法中获取锁前的中断标识检测。

读写锁ReentrantReadWriteLock

实现原理,重写并拆分了AbstractQueuedSynchronizer中的state状态,高16位存储读锁的状态,低16位存储写锁的状态。
对于写锁来说,只需要判断state>0则说明有线程占有锁,就需要进入阻塞队列,而对于读锁来说,先判断state,等于0说明无线程占用,>0再判断是否写线程占用(低16位),写占用则进入阻塞队列,读占用则获取到锁。
写线程占有较高优先级,因为不这样做的话,可能多个读线程一直执行,导致写线程饥饿。

Condition

final ReentrantLock lock = new ReentrantLock(); 
private final Condition notEmpty = lock.newCondition(); 
private final Condition notFull =  Lock.newCondition();

notEmpty.await();//阻塞
notEmpty.signal();//唤醒

Condition实现原理

所有的condition都是借助ConditionObject对象来实现。对象里面维护一个双向阻塞线程链表,通过这个链表来进行统一的唤醒操作。

StampedLock锁

jdk1.8以后提供,相比较于ReentrantWriteLock。读写默认是不互斥的。只有当读写冲突时,才会升级为互斥。数据读出来后会有个版本号,再使用之前会用版本号校验是否被改过,若被改过才会去竞争锁,重新读数据。

StampedLock stampLock = new StampedLock();
long stamp=stampLock.writeLock();//上写锁
stampLock.unWriteLock(stamp);//解锁

long rStamp=stampLock.tryOptimisticRead();//乐观读
if(!stampLock.validate(rStamp)){
    stampLock.readLock();//加读锁
    stampLock.unReadLock(rStamp);//解读锁
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

搬砖工-->攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值