JUC之深入理解ReentrantLock

并发编程-JUC并发工具类应用场景详解 ReentrantLock具体应用场景如下:1. 解决多线程竞争资源的问题,例如多个线程同时对同一个数据库进行写操作,可以使用ReentrantLock保证每次 只有一个线程能够写入。2. 实现多线程任务的顺序执行,例如在一个线程执行完某个任务后,再让另一个线程执行任务。3. 实现多线程等待/通知机制,例如在某个线程执行完某个任务后,通知其他线程继续执行任务。 阅读详情

1. 简介

ReentrantLock,可重入锁,是一种递归无阻塞的同步机制。它可以等同于 synchronized 的使用,但是 ReentrantLock 提供了比 synchronized 更强大、灵活的锁机制,可以减少死锁发生的概率。

一个可重入的互斥锁定 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁定相同的一些基本行为和语义,但功能更强大。

ReentrantLock 将由最近成功获得锁定,并且还没有释放该锁定的线程所拥有。当锁定没有被另一个线程所拥有时,调用 lock 的线程将成功获取该锁定并返回。如果当前线程已经拥有该锁定,此方法将立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此情况是否发生。

ReentrantLock 还提供了公平锁和非公平锁的选择,通过构造方法接受一个可选的 fair 参数(默认非公平锁):当设置为 true 时,表示公平锁;否则为非公平锁。

公平锁与非公平锁的区别在于,公平锁的锁获取是有顺序的。但是公平锁的效率往往没有非公平锁的效率高,在许多线程访问的情况下,公平锁表现出较低的吞吐量。

ReentrantLock 整体结构如下图:

  • ReentrantLock 实现 Lock 接口,基于内部的 Sync 实现。

  • Sync 实现 AQS ,提供了 FairSync 和 NonFairSync 两种实现。

2. Sync 抽象类

Sync 是 ReentrantLock 的内部静态类,实现 AbstractQueuedSynchronizer 抽象类,同步器抽象类。它使用 AQS 的 state 字段,来表示当前锁的持有数量,从而实现可重入的特性。

 /**
     * 该锁同步控制的一个基类.下边有两个子类:非公平机制和公平机制.使用了AbstractQueuedSynchronizer类的
     */
    static abstract class Sync extends AbstractQueuedSynchronizer

2.1 lock

基于CAS尝试将state(锁数量)从0设置为1

A、如果设置成功,设置当前线程为独占锁的线程;

B、如果设置失败,还会再获取一次锁数量,

B1、如果锁数量为0,再基于CAS尝试将state(锁数量)从0设置为1一次,如果设置成功,设置当前线程为独占锁的线程;

B2、如果锁数量不为0或者上边的尝试又失败了,查看当前线程是不是已经是独占锁的线程了,如果是,则将当前的锁数量+1;如果不是,则将该线程封装在一个Node内,并加入到等待队列中去。等待被其前一个线程节点唤醒。

/**
 * Performs {@link Lock#lock}. The main reason for subclassing
 * is to allow fast path for nonfair version.
 */
abstract void lock();
  • 执行锁。抽象了该方法的原因是,允许子类实现快速获得非公平锁的逻辑。

2.2 nonfairTryAcquire

nonfairTryAcquire(int acquires) 方法,非公平锁的方式获得锁。代码如下:

final boolean nonfairTryAcquire(int acquires) {
    //当前线程
    final Thread current = Thread.currentThread();
    //获取同步状态
    int c = getState();
    //state == 0,表示没有该锁处于空闲状态
    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;
}
  • 该方法主要逻辑:首先判断同步状态state == 0?

    • 如果是,表示该锁还没有被线程持有,直接通过CAS获取同步状态。

      • 如果成功,返回 true 。

      • 否则,返回 false 。

    • 如果不是,则判断当前线程是否为获取锁的线程?

      • 如果是,则获取锁,成功返回 true 。成功获取锁的线程,再次获取锁,这是增加了同步状态 state 。通过这里的实现,我们可以看到上面提到的 “它使用 AQS 的 state 字段,来表示当前锁的持有数量,从而实现可重入的特性”。

      • 否则,返回 false 。

  • 理论来说,这个方法应该在子类 FairSync 中实现,但是为什么会在这里呢?在下文的 ReentrantLock.tryLock()中,详细解析。

2.3 tryRelease

tryRelease(int releases) 实现方法,释放锁。代码如下:

protected final boolean tryRelease(int releases) {
    // 减掉releases
    int c = getState() - releases;
    // 如果释放的不是持有锁的线程,抛出异常
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    // state == 0 表示已经释放完全了,其他线程可以获取同步状态了
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}
  • 通过判断判断是否为获得到锁的线程,保证该方法线程安全。

  • 只有当同步状态彻底释放后,该方法才会返回 true 。当 state == 0 时,则将锁持有线程设置为 null ,free= true,表示释放成功。

2.4 其他实现方法

// 是否当前线程独占
@Override
protected final boolean isHeldExclusively() {
    // While we must in general read state before owner,
    // we don't need to do so to check if current thread is owner
    return getExclusiveOwnerThread() == Thread.currentThread();
}

// 新生成条件
final ConditionObject newCondition() {
    return new ConditionObject();
}

// Methods relayed from outer class

// 获得占用同步状态的线程
final Thread getOwner() {
    return getState() == 0 ? null : getExclusiveOwnerThread();
}

// 获得当前线程持有锁的数量
final int getHoldCount() {
    return isHeldExclusively() ? getState() : 0;
}

// 是否被锁定
final boolean isLocked() {
    return getState() != 0;
}

/**
 * Reconstitutes the instance from a stream (that is, deserializes it).
 * 自定义反序列化逻辑
 */
private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    s.defaultReadObject();
    setState(0); // reset to unlocked state
}
  • 从这些方法中,我们可以看到,ReentrantLock 是独占获取同步状态的模式。

3. Sync 实现类

3.1 NonfairSync

获取锁的步骤

基于CAS尝试将state(锁数量)从0设置为1

A、如果设置成功,设置当前线程为独占锁的线程;

B、如果设置失败,还会再获取一次锁数量,

B1、如果锁数量为0,再基于CAS尝试将state(锁数量)从0设置为1一次,如果设置成功,设置当前线程为独占锁的线程;

B2、如果锁数量不为0或者上边的尝试又失败了,查看当前线程是不是已经是独占锁的线程了,如果是,则将当前的锁数量+1;如果不是,则将该线程封装在一个Node内,并加入到等待队列中去。等待被其前一个线程节点唤醒。

NonfairSync 是 ReentrantLock 的内部静态类,实现 Sync 抽象类,非公平锁实现类。

3.1.1 lock

lock() 实现方法,首先基于 AQS state 进行 CAS操作,将 0 设置为1 。若成功,则获取锁成功。若失败,执行 AQS 的正常的同步状态获取逻辑。代码如下:

/**
 * 1)首先基于CAS将state(锁数量)从0设置为1,如果设置成功,设置当前线程为独占锁的线程;-->请求成功-->第一次插队
 * 2)如果设置失败(即当前的锁数量可能已经为1了,即在尝试的过程中,已经被其他线程先一步占有了锁),这个时候当前线程执行acquire(1)方法
 	//获取锁的方法
    public final void acquire(int arg) {
        if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();//中断自己
    }

  * 2.1)acquire(1)方法首先调用下边的tryAcquire(1)方法,在该方法中,首先获取锁数量状态,
  * 2.1.1)如果为0(证明该独占锁已被释放,当下没有线程在使用),这个时候我们继续使用CAS将state(锁数量)从0设置为1,如果设置成功,当前线程独占锁;-->请求成功-->第二次插队;当然,如果设置不成功,直接返回false
  * 2.2.2)如果不为0,就去判断当前的线程是不是就是当下独占锁的线程,如果是,就将当前的锁数量状态值+1(这也就是可重入锁的名称的来源)-->请求成功
      * 
      * 下边的流程一句话:请求失败后,将当前线程链入队尾并挂起,之后等待被唤醒。
      * 
  * 2.2.3)如果最后在tryAcquire(1)方法中上述的执行都没成功,即请求没有成功,则返回false,继续执行acquireQueued(addWaiter(Node.EXCLUSIVE), arg)方法
  * 2.2)在上述方法中,首先会使用addWaiter(Node.EXCLUSIVE)将当前线程封装进Node节点node,然后将该节点加入等待队列(先快速入队,如果快速入队不成功,其使用正常入队方法无限循环(即自旋)一直到Node节点入队为止)
  * 2.2.1)快速入队:如果同步等待队列存在尾节点,将使用CAS(compareAndSetTail(pred, node))尝试将尾节点设置为node,并将之前的尾节点插入到node之前(即Node pred = tail;node.prev = pred;)
  * 2.2.2)正常入队:如果同步等待队列不存在尾节点或者上述CAS尝试不成功的话,就执行正常入队(enq(node);该方法是一个无限循环的过程,即直到入队为止)-->第一次阻塞
  * 2.2.2.1)如果尾节点为空(初始化同步等待队列),创建一个dummy节点,并将该节点通过CAS尝试设置到头节点上去,设置成功的话,将尾节点也指向该dummy节点(即头节点和尾节点都指向该dummy节点)
  * 2.2.2.1)如果尾节点不为空,执行与快速入队相同的逻辑,即使用CAS尝试将尾节点设置为node,并将之前的尾节点插入到node之前
 * 最后,如果顺利入队的话,就返回入队的节点node,如果不顺利的话,无限循环去执行2.2)下边的流程,直到入队为止
 * 2.3)node节点入队之后,就去执行acquireQueued(final Node node, int arg)(这又是一个无限循环的过程,这里需要注意的是,无限循环等于阻塞,多个线程可以同时无限循环--每个线程都可以执行自己的循环,这样才能使在后边排队的节点不断前进)
 * 2.3.1)获取node的前驱节点p,如果p是头节点,就继续使用tryAcquire(1)方法去尝试请求成功,-->第三次插队(当然,这次插队不一定不会使其获得执行权,请看下边一条),
 * 2.3.1.1)如果第一次请求就成功,不用中断自己的线程,如果是之后的循环中将线程挂起之后又请求成功了,使用selfInterrupt()中断自己
 * (注意p==head&&tryAcquire(1)成功是唯一跳出循环的方法,在这之前会一直阻塞在这里,直到其他线程在执行的过程中,不断的将p的前边的节点减少,直到p成为了head且node请求成功了--即node被唤醒了,才退出循环)
 * 2.3.1.2)如果p不是头节点,或者tryAcquire(1)请求不成功,就去执行shouldParkAfterFailedAcquire(Node pred, Node node)来检测当前节点是不是可以安全的被挂起,
 * 2.3.1.2.1)如果node的前驱节点pred的等待状态是SIGNAL(即可以唤醒下一个节点的线程的状态),则node节点的线程可以安全挂起,返回true,执行2.3.1.3)
 * 2.3.1.2.2)如果node的前驱节点pred的等待状态是CANCELLED,则pred的线程被取消了,我们会将pred之前的连续几个被取消的前驱节点从队列中剔除,返回false(即不能挂起),如下:
 do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
 
 之后继续执行2.3)中上述的代码的cancelAcquire(node);
 * 2.3.1.2.3)如果node的前驱节点pred的等待状态是除了上述两种的其他状态,则使用CAS尝试将前驱节点的等待状态设为SIGNAL,并返回false(因为CAS可能会失败,这里不管失败与否,都返回false,下一次执行该方法的之后,pred的等待状态就是SIGNAL了),之后继续执行2.3)中上述的代码的cancelAcquire(node);
 * 2.3.1.3)如果可以安全挂起,就执行parkAndCheckInterrupt()挂起当前线程,之后,继续执行2.3)中之前的代码
* 最后,直到该节点的前驱节点p之前的所有节点都执行完毕为止,我们的p成为了头节点,并且tryAcquire(1)请求成功,跳出循环,去执行。
 * (在p变为头节点之前的整个过程中,我们发现这个过程是不会被中断的)
 * 2.3.2)当然在2.3.1)中产生了异常,我们就会执行cancelAcquire(Node node)取消node的获取锁的意图。
*/
        final void lock() {
            if (compareAndSetState(0, 1))//如果CAS尝试成功
                setExclusiveOwnerThread(Thread.currentThread());//设置当前线程为独占锁的线程
            else
                acquire(1);
        }
  • 优先基于 AQS state 进行 CAS 操作,已经能体现出非公平锁的特点。因为,此时有可能有 N + 1 个线程正在获得锁,其中 1 个线程已经获得到锁,释放的瞬间,恰好被新的线程抢夺到,而不是排队的 N 个线程。

3.1.2 tryAcquire

tryAcquire(int acquires) 实现方法,非公平的方式,获得同步状态。代码如下:

protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}
  • 直接调用 nonfairTryAcquire(int acquires) 方法,非公平锁的方式获得锁。

/**
         * 非公平锁中被tryAcquire调用
         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();//获取当前线程
            int c = getState();//获取锁数量
            if (c == 0) {//如果锁数量为0,证明该独占锁已被释放,当下没有线程在使用
                if (compareAndSetState(0, acquires)) {//继续通过CAS将state由0变为1,注意这里传入的acquires为1
                    setExclusiveOwnerThread(current);//将当前线程设置为独占锁的线程
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {//查看当前线程是不是就是独占锁的线程
                int nextc = c + acquires;//如果是,锁状态的数量为当前的锁数量+1
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);//设置当前的锁数量
                return true;
            }
            return false;
        }

3.2 FairSync

FairSync 是 ReentrantLock 的内部静态类,实现 Sync 抽象类,公平锁实现类。

lock的步骤:获取一次锁数量,

B1、如果锁数量为0,如果当前线程是等待队列中的头节点,基于CAS尝试将state(锁数量)从0设置为1一次,如果设置成功,设置当前线程为独占锁的线程;

B2、如果锁数量不为0或者当前线程不是等待队列中的头节点或者上边的尝试又失败了,查看当前线程是不是已经是独占锁的线程了,如果是,则将当前的锁数量+1;如果不是,则将该线程封装在一个Node内,并加入到等待队列中去。等待被其前一个线程节点唤醒。

3.2.1 lock

lock() 实现方法,代码如下:

final void lock() {
    acquire(1);
}
  • 直接执行 AQS 的正常的同步状态获取逻辑。

3.2.2 tryAcquire

tryAcquire(int acquires) 实现方法,公平的方式,获得同步状态。代码如下:

 	 /**
         * 获取公平锁的方法
         * 1)获取锁数量c
         * 1.1)如果c==0,如果当前线程是等待队列中的头节点,使用CAS将state(锁数量)从0设置为1,如果设置成功,当前线程独占锁-->请求成功
         * 1.2)如果c!=0,判断当前的线程是不是就是当下独占锁的线程,如果是,就将当前的锁数量状态值+1(这也就是可重入锁的名称的来源)-->请求成功
         * 最后,请求失败后,将当前线程链入队尾并挂起,之后等待被唤醒。
         */
protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        if (!hasQueuedPredecessors() && // <1>
                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;
}

比较非公平锁和公平锁获取同步状态的过程,会发现两者唯一的区别就在于,公平锁在获取同步状态时多了一个限制条件 <1> 处的 hasQueuedPredecessors() 方法,是否有前序节点,如果返回true,即表示自己不是首个等待获取同步状态的节点。代码如下:

// AbstractQueuedSynchronizer.java
public final boolean hasQueuedPredecessors() {
    Node t = tail;  //尾节点
    Node h = head;  //头节点
    Node s;

    //头节点 != 尾节点
    //同步队列第一个节点不为null
    //当前线程是同步队列第一个节点
    return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
}
  • 该方法主要做一件事情:主要是判断当前线程是否位于 CLH 同步队列中的第一个。如果是则返回 true ,否则返回 false 。

总结:公平锁与非公平锁对比

  • FairSync:lock()少了插队部分(即少了CAS尝试将state从0设为1,进而获得锁的过程)

  • FairSync:tryAcquire(int acquires)多了需要判断当前线程是否在等待队列首部的逻辑(实际上就是少了再次插队的过程,但是CAS获取还是有的)。

最后说一句,

  • ReentrantLock是基于AbstractQueuedSynchronizer实现的,AbstractQueuedSynchronizer可以实现独占锁也可以实现共享锁,ReentrantLock只是使用了其中的独占锁模式

4. Lock 接口

java.util.concurrent.locks.Lock 接口,定义方法如下:

void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();

5. ReentrantLock

java.util.concurrent.locks.ReentrantLock ,实现 Lock 接口,重入锁。

ReentrantLock 的实现方法,基本是对 Sync 的调用。

5.1 构造方法

public ReentrantLock() {
    sync = new NonfairSync();
}

public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}
  • 基于 fair 参数,创建 FairSync 还是 NonfairSync 对象。

5.2 lock

/**
     *获取一个锁
     *三种情况:
     *1、如果当下这个锁没有被任何线程(包括当前线程)持有,则立即获取锁,锁数量==1,之后再执行相应的业务逻辑
     *2、如果当前线程正在持有这个锁,那么锁数量+1,之后再执行相应的业务逻辑
     *3、如果当下锁被另一个线程所持有,则当前线程处于休眠状态,直到获得锁之后,当前线程被唤醒,锁数量==1,再执行相应的业务逻辑
     */
public void lock() {
    sync.lock();	//调用NonfairSync(非公平锁)或FairSync(公平锁)的lock()方法
}

//获取公平锁
/**
     *获取一个锁
     *三种情况:
     *1、如果当下这个锁没有被任何线程(包括当前线程)持有,则立即获取锁,锁数量==1,之后被唤醒再执行相应的业务逻辑
     *2、如果当前线程正在持有这个锁,那么锁数量+1,之后被唤醒再执行相应的业务逻辑
     *3、如果当下锁被另一个线程所持有,则当前线程处于休眠状态,直到获得锁之后,当前线程被唤醒,锁数量==1,再执行相应的业务逻辑
     */

5.3 lockInterruptibly

@Override
public void lockInterruptibly() throws InterruptedException {
    sync.acquireInterruptibly(1);	
}

 

6.synchronized 和 ReentrantLock 异同?

  • 相同点

    • 都实现了多线程同步和内存可见性语义。

    • 都是可重入锁。

  • 不同点

    • 同步实现机制不同

      • synchronized 通过 Java 对象头锁标记和 Monitor 对象实现同步。

      • ReentrantLock 通过CAS、AQS(AbstractQueuedSynchronizer)和 LockSupport(用于阻塞和解除阻塞)实现同步。

    • 可见性实现机制不同

      • synchronized 依赖 JVM 内存模型保证包含共享变量的多线程内存可见性。

      • ReentrantLock 通过 ASQ 的 volatile state 保证包含共享变量的多线程内存可见性。

    • 使用方式不同

      • synchronized 可以修饰实例方法(锁住实例对象)、静态方法(锁住类对象)、代码块(显示指定锁对象)。

      • ReentrantLock 显示调用 tryLock 和 lock 方法,需要在 finally 块中释放锁。

    • 功能丰富程度不同

      • synchronized 不可设置等待时间、不可被中断(interrupted)。

      • ReentrantLock 提供有限时间等候锁(设置过期时间)、可中断锁(lockInterruptibly)、condition(提供 await、condition(提供 await、signal 等方法)等丰富功能

    • 锁类型不同

      • synchronized 只支持非公平锁。

      • ReentrantLock 提供公平锁和非公平锁实现。当然,在大部分情况下,非公平锁是高效的选择。

      • ReentrantLock 支持中断处理,且性能较 synchronized 会好些。

在 synchronized 优化以前,它的性能是比 ReenTrantLock 差很多的,但是自从 synchronized 引入了偏向锁,轻量级锁(自旋锁)后,两者的性能就差不多了,在两种方法都可用的情况下,官方甚至建议使用 synchronized 。

并且,实际代码实战中,可能的优化场景是,通过读写分离,进一步性能的提升,所以使用 ReentrantReadWriteLock 。

 

 

并发编程(七)——JUC并发工具 CountDownLatch就是JUC包下的一个工具,整个工具最核心的功能就是计数器。如果有三个业务需要并行处理,并且需要知道三个业务全部都处理完毕了。需要一个并发安全的计数器来操作。CountDownLatch就可以实现。给CountDownLatch设置一个数值。可以设置3。每个业务处理完毕之后,执行一次countDown方法,指定的3每次在执行countDown方法时,对3进行-1。主线程可以在业务处理时,执行await,主线程会阻塞等待任务处理完毕。 阅读详情

相关推荐

java并发编程专题(五)----详解(JUC)ReentrantLock

主要介绍了java(JUC)ReentrantLock的的相关资料,文中讲解非常详细,实例代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下

JUC并发编程(3)——偏向锁、轻量锁、重量锁、自旋锁

一、对象的内存布局 在HotSpot虚拟机中,对象在堆内存中的存储布局可以划分为三个部分:对象头、实例数据和对齐填充。 1.1 对象头 对象头分为两个部分,第一部分用于存储对象自身运行时数据,如哈希码、GC分代年龄、锁状态标识、线程持有的锁、偏向线程ID、偏向时间戳等,官方统称为Mark Word;第二部分是类型指针,指向方法区的运行时数据区。 普通对象 数组对象 Mark Word Mark Word在32位JVM中的长度是32bit,在64位JVM中长度是64bit,在32位JVM中的结构为: 1

qq_51114283的博客 505

【Chisel】2.4 时序逻辑

2.4 时序逻辑@[TOC](2.4 时序逻辑)前言寄存器(`Reg`)实例Chisel的状态函数实例2 RegNext实例3 RegInit移位器附录 显式的时钟信号和复位信号 前言 没有状态机的逻辑电路是不完整的,没有状态机的逻辑电路是不完整的,没有状态机的逻辑电路是不完整的,重要的事情说三遍。 这一节我们将要学习Chisel中的时序逻辑。在最后我们会实现一个移位器。 这里你需要知道的是,前面的这几节实际上都是对Chisel的基础语法的学习,它并不会给你带来很大的“惊喜”。Chisel真正的作用是把电路

快乐学习小猪猪的博客 842

JUC并发编程01——谈谈锁机制:轻量级锁、重量级锁、偏向锁、锁消除与锁优化

1.为什么要有并发编程 计算机的cpu与I/O的效率并不是完全一致的,CPU的处理速度快时,在进行I/O操作时,可能会导致CPU空闲的状态,为了最打程度的利用cpu的资源,开发人员创造了并发编程,进程通过轮换可以最大程度的利用cpu的资源,同时给用户进程在同步执行的错觉。但是进程之间并不会共享数据,同时上下文的切换也比较耗时,线程横空出世,同一个进程中的不同线程之间内存共享一片内存区域,线程上下文切换也很轻量级。juc是java官方提供的线程操作的jar包,可以尽可能的降低我们并发编程的难度。 2.锁机制

半旧518的博客 927

【软考高级架构设计师】——2025年上半年软考真题(回忆版)

a)异构计算和算法优化b)资源抽象和容器控制c)安全和隔离(大致是这个意思)

小志的博客 4824

Python实战:用SkillMetrics库5分钟搞定泰勒图绘制(附完整代码)

本文详细介绍了如何使用Python的SkillMetrics库快速绘制专业泰勒图,以直观对比多个模型的预测性能。通过整合相关系数、标准差和中心化均方根误差三个核心指标,该工具能帮助数据科学家和研究者高效完成模型评估与可视化,提升分析报告质量。文章提供了从环境配置、数据准备到高级定制与子图对比的完整代码示例。

7z8x2c4v6b9的博客 371

JUC 锁之 ReentrantLock 详解

一 概述 先提出一些问题: 什么是可重入,什么是可重入锁? 它用来解决什么问题? ReentrantLock的核心是AQS,那么它怎么来实现的,继承吗? 说说其类内部结构关系。 ReentrantLock是如何实现公平锁的? ReentrantLock是如何实现非公平锁的? ReentrantLock默认实现的是公平还是非公平锁? 使用ReentrantLock实现公平和非公平锁的示例? ReentrantLock和Synchronized的对比? 接下来对 ReentrantLock 的分析,我们会一

liuwg1226的专栏 459

DAZ STUDIO 快速渲染技巧

DAZ STUDIO 快速渲染技巧: 本文将向您展示几个快速渲染技巧。您将学习如何使您的Daz Iray渲染和照明在Daz工作室内更快。 当你有一个大场景,这可能需要很多小时进行渲染。 但是如果你想大幅度降低渲染时间呢?这篇文章的提示应该能让你达到这个目标。 首先,我们需要弄清楚一件事——没有“完美的环境或设置”这样的东西。是因为渲染设置是高度个性化和主观性的东西,这主要取决于场景和硬件。如果你有一个功能强大的计算机,你可以允许更多的低渲染时间,反之亦然。因此,一切都取决于您尝试渲染的对象和机器。

DAZSTUDIO的博客 9641

深入理解ReentrantLock

java并发ReentrantLock锁分析

zhangzhigan1202的博客 348

基于陀螺仪航向反馈的轮式机器人PID直线控制

航向角控制是移动机器人实现稳定直线运动的基础技术,其本质是通过实时感知机体朝向偏差并动态调节驱动输出,以抵消机械不对称、轮径误差等固有扰动。该方法依托陀螺仪测量角速度并积分解算航向角,结合离散化PID算法生成补偿性PWM指令,在嵌入式平台(如STM32)上构建低延迟闭环。相比依赖编码器的速度闭环,它规避了轮径标定与安装偏心等误差源,显著提升低成本平台的工程鲁棒性与部署效率。典型应用场景包括教育机器人直线循迹、AGV基础导航模块开发及IMU-PID融合控制原型验证。

web39explorer的博客 1108

分析4-20mA检查电路分析

本文介绍了一种工业领域常用的4-20mA电流信号调理电路,可将标准电流信号转换为适合MCU采集的电压信号。电路包含三个关键模块:首先通过10Ω取样电阻将4-20mA电流转换为0.04-0.2V电压;然后采用同向比例运算放大器KTA333-ST5进行信号放大;最后通过二阶有源低通滤波器滤除工业环境中的高频干扰。文章详细分析了各模块的工作原理和参数设计,并以压力传感器和温度变送器为例说明了实际应用中的参数调整方法。该电路具有抗干扰能力强、精度高等特点,适用于工业压力、温度等模拟量信号的采集处理。

qq_37999850的博客 1325

JUC AQS ReentrantLock源码分析(一)

Java的内置锁一直都是备受争议的,在JDK 1.6之前,synchronized这个重量级锁其性能一直都是较为低下,虽然在1.6后,进行大量的锁优化策略,但是与Lock相比synchronized还是存在一些缺陷的:虽然synchronized提供了便捷性的隐式获取锁释放锁机制(基于JVM机制),但是它却缺少了获取锁与释放锁的可操作性,可中断、超时获取锁,且它为独占式在高并发场景下性能大打折扣。...

java_lyvee的专栏 3万+

Loop Engineering 来了:从写 Prompt 到设计 Loop,AI 编程的第四次范式跃迁

文章摘要: Loop Engineering是AI编程领域的新范式,标志着从"人手动喂指令"到"设计自驱动循环"的跃迁。其核心在于通过五个组件(定时器、工作空间、知识体系、连接器和子Agent验证)构建自动化任务流,使AI系统能自主运行。这一概念的火爆源于模型能力和工具链的成熟,使得任务设计成为关键瓶颈。作者指出,从Prompt到Loop的四次范式跃迁(语言学→信息科学→控制论→管理学)反映了人机协作关系的根本变化:人类角色从执行者逐渐退居为目标设定者。落地Loop Engineering的真正挑战在于目标

少说,多做 329

深入理解 JUC:ReentrantLock

ReentrantLock 译为可重入锁,我们在使用时总是将其与 synchronized 关键字进行对比,实际上 ReentrantLock 与 synchronized 关键字在使用上具备相同的语义,区别仅在于 ReentrantLock 相对于 synchronized 关键字留给开发者的可操作性更强,所以在使用上更加灵活,当然凡事都有两面,灵活的背后也暗藏着更加容易出错的风险。 尽管语义相同,但 ReentrantLock 和 synchronized 关键字背后的实现机制却大相径庭。前面的文章中我

qq_44457886的博客 236

使用 Simulink + Simscape Electrical 实现一个变压器耦合式单相全波整流器的仿真模型

本文介绍了基于Simulink的变压器耦合式单相全波整流器建模与仿真方法。详细说明了从项目创建、模块添加、电路搭建到参数配置的完整建模过程,重点分析了整流器的效率与损耗特性,包括变压器损耗和二极管导通损耗。通过仿真展示了输入输出波形特征,并提出了选用高效元件、优化变压器设计等改进建议。该案例为电力电子系统建模提供了实用参考,有助于深入理解整流电路工作原理和性能优化方法。

amy_mhd的博客 185

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

深入理解 JUC 的 ReentrantLock 加锁和解锁流程

下面这张图 你需要明白的是先讲解一下大概的流程ReentrantLock 首先lock-》 公平锁或者非公平锁的 lock()-》acquire(1) 就会跑到AQS的代码中。

sjisbbeksudh的博客 523

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

深入理解JUC——AQS 及 ReentrantLock

AQS 阻塞式锁和相关的同步器工具的框架。核心思想是:如果被请求的共享资源空闲,则将资源分配给工作线程,并将共享资源设置为锁定的状态;如果资源被占用的话,就需要一套线程阻塞等待以及被唤醒时锁分配的机制,AQS将线程封装成节点,进入到队列当中(FIFO的双向队列),等待唤醒。...

Inception查缺补漏 298

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

【JUC系列-15】深入理解CompletableFuture的基本使用

深入理解CompletableFuture的基本使用

zhenghuishengq的博客 6293

别说我自私,大牛亲码607页JUC源码分析来了

你知道java中的juc是什么意思吗?很多人表示对于java juc不是很了解

m0_57042151的博客 199

使用ReentrantLock,以及synchronized实现阻塞队列

使用JUC类,以及非JUC类实现阻塞队列 1:使用JUC类的ReentrantLock实现阻塞队列 1.1:主要使用lock.newCondition() 来声明两个Condition ,使用Condition的await 实现阻塞,使用signalAll来实现唤醒。Condition 的await,signalAll类似于Object的wait,notifyAll 比较相似;后续会专门列...

xiao326791055的博客 1331

JUC并发编程基础AQS

获取当前线程获取当前锁的状态state,默认为0判断是否被加锁,就是state不为0的时候第一种没有加锁,调用这个方法compareAndSetState,修改state的值将0变为1,接着讲属性exclusiveOwnerThread的值赋为当前线程,至此当前线程加锁成功!第二种加锁,判断加锁的线程是否为当前线程,如果是则表示重入,将state的值累加就行,否则就是加锁失败1、封装当前获取锁的线程,封装成一个Node节点第一种。条件队列。...

技术分享、唠嗑水文、如有不周、还望海涵 655

深入理解Java多线程(三)JUC基础篇

这篇文章主要侧重讲JUC的多数类的使用,文章里贴了很多练习的代码,可以通过代码更加深刻的了解这些类的功能。 这篇文章主要总结了volatile、原子类、ReentrantLock、CountDownLatch、CyclicBarrier、Phaser、Semphore、Exchanger的使用,然后进行了一些对比。 个人博客:https://www.elltor.com/archives/110.html 欢迎访问,相互学习,共同进步???? 文章目录volatilevolatile使用volatile

Elltor 721

JUC——JUC开发简介(一)

前言 JUC是Java5.0开始提供的一组专门实现多线程并发处理的开发框架,利用JUC开发架构可以有效的解决实际线程项目开发之中出现的死锁、阻塞、资源访问与公平机制。 此笔记主要记录java.util.concurrent开发包之中的各个核心组成类的使用、操作原理分析,并且通过具体的实际代码对多线程的开发实际环境进行原理分析,同时方便自己随时复习掌握。 此系列学习笔记来源于课程MLDN《JU...

weixin_34104341的博客 273

【JUC】核心知识点归纳

本文梳理了线程基础(4种创建方式与6种状态流转)、线程安全的3大特性(原子性、可见性、有序性)、线程池的优势(资源复用、管理、响应提速)以及ThreadLocal的线程隔离机制(原理与内存泄漏防范)。重点对比了synchronized(JVM内置锁,支持锁升级)与ReentrantLock(基于AQS,支持公平/非公平锁)的特性差异,为面试和开发提供核心知识参考。

ajsbxi的博客 830

JUC(一)- JUC学习概览 - 对JUC有一个整体的认识

JUC学习概览

hiliang521的博客 1935

java并发编程开发(思维导图)

java开发(思维导图)

qq_18846731的博客 379
上一篇: JUC之深入理解AQS
下一篇: JUC之深入理解ReentrantReadWriteLock
striveb
博客等级 码龄10年 242粉丝 117原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值