深入理解acquire和release原理源码及lock独有特性acquireInterruptibly和tryAcquireNanos

Lock是一个接口,通常会用ReentrantLock(可重入锁)来实现这个接口。

独占式获取锁

1.lock()

ReentrantLock lock=new ReentrantLock();
lock.lock();

当获取锁时通常会调用ReentrantLock的lock()方法。而lock()方法在ReentrantLock是一个抽象方法,默认情况下ReentrantLock是一个非公平锁,
lock()方法具体实现在ReentrantLock的静态内部类NonfairSync中,源码如下:

public class ReentrantLock implements Lock, java.io.Serializable {
   
        abstract static class Sync extends AbstractQueuedSynchronizer {
   
        abstract void lock();
        }
        static final class NonfairSync extends Sync {
   
        final void lock() {
   
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
}        

这里的lock()方法先通过CAS将state的值从0变为1(ReentrantLock用state表示“持有锁的线程已经重复获取该锁的次数”):当state实际值等于预期值0时,表示当前没有线程持有该锁,更新state值为1,将ExclusiveOwnerThread的值为当前线程(Exclusive是独占的意思,ReentrantLock用exclusiveOwnerThread表示“持有锁的线程”),那么该线程获取锁成功。如果CAS失败。说明state实际值并不是0,也就是说已经有线程持有该锁,此时执行acquire(1)再次请求锁。

2.acquire()

调用acquire():会调用ReentrantLock的静态内部AbstractQueuedSynchronizer的acquire方法()。看源码:

public abstract class AbstractQueuedSynchronizer
    extends AbstractOwnableSynchronizer
    implements java.io.Serializable {
   
    /**
     * Acquires in exclusive mode, ignoring interrupts.  Implemented
     * by invoking at least once {@link #tryAcquire},
     * returning on success.  Otherwise the thread is queued, possibly
     * repeatedly blocking and unblocking, invoking {@link
     * #tryAcquire} until success.  This method can be used
     * to implement method {@link Lock#lock}.
     *
     * @param arg the acquire argument.  This value is conveyed to
     *        {@link #tryAcquire} but is otherwise uninterpreted and
     *        can represent anything you like.
     */
    public final void acquire(int arg) {
   
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
}

从注释我们可以了解到acqiure的作用:我理解的是acquire请求独占锁,忽略所有中断,至少执行一次tryAcquire,如果tryAcquire()再次获取锁成功就直接退出,否则线程进入阻塞- - -唤醒2种状态切换中,直到tryAcquire成功。

可以看到if语句是&&,那么先看tryAcquire()方法。
注:以下方法没有特殊表明都在静态内部类AQS中。
3.tryAcquire()

acquire失败后再次用tryAcquire()获取同步状态。

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

nonfairTryAcquire()再次获取锁,先判断state是否为0,如果为0即没有线程获取该锁,通过CAS该线程获取到锁。如果state不为0,判断当前线程是否是getExclusiveOwnerThread即持有锁线程,是的话,就将state++,也就是可重入的体现。否则再次获取同步状态失败。
当state=0通过CAS保证同步,即同一个时刻只有一个线程可以获取到锁,但是如果当前线程是持有锁线程并没有保证同步是因

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Python解释器中,全局解释器锁(Global Interpreter Lock)保证了多线程之间的安全,但它也导致了多线程中Python代码执行的并发性问题。当多个线程同时执行Python代码时,只有一个线程能够持有全局解释器锁,其他线程必须等待该线程释放锁之后才能继续执行。这可能会导致线程的长时间等待,从而影响程序的性能。 为了解决这个问题,Python提供了一些API,比如PyEval_AcquireLock()和PyEval_ReleaseLock()。这两个函数可以在多线程环境下控制全局解释器锁的获取和释放,从而实现线程安全的Python代码执行。 以下是一个使用PyEval_AcquireLock()和PyEval_ReleaseLock()的示例: ```python import threading def run_python_code(code): # 获取全局解释器锁 PyEval_AcquireLock() try: # 执行Python代码 exec(code) finally: # 释放全局解释器锁 PyEval_ReleaseLock() # 创建两个线程 t1 = threading.Thread(target=run_python_code, args=("print('Hello from thread 1!')",)) t2 = threading.Thread(target=run_python_code, args=("print('Hello from thread 2!')",)) # 启动线程 t1.start() t2.start() # 等待线程结束 t1.join() t2.join() ``` 在上面的示例中,我们创建了两个线程,并在每个线程中执行了一段Python代码。在执行代码之前,我们使用PyEval_AcquireLock()获取了全局解释器锁,在执行完代码之后使用PyEval_ReleaseLock()释放了锁。这样可以确保代码的线程安全性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值