Loading

ReentrantLock原理

ReentrantLock

实现了Lock接口,是一个可重入且独占式的锁,与 synchronized 关键字类似,但更加灵活。

内部类 Sync 实现了 AQS,且基于Sync实现了公平锁和非公平锁。但默认使用非公平锁。

image-20230728200553291

公平锁、非公平锁原理

ReentrantLock中的Sync继承了AQS,实现了模板方法,通过FairSync继承Sync实现公平锁,通过NonfairSync继承Sync实现非公平锁。

非公平锁

通过NonfairSync实现,tryAquice方法重写调用了SyncnonfairTryAcquire方法

final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread(); // 1
    int c = getState();							// 2
    if (c == 0) {								// 3
        if (compareAndSetState(0, acquires)) {		// 4
            setExclusiveOwnerThread(current);		// 5
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {	// 6
        int nextc = c + acquires;					// 7
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);							// 8
        return true;
    }
    return false;							
}
  1. 获取要加锁的线程
  2. 获取此时锁的状态
  3. 锁状态为0,即无锁状态
  4. 无锁则用CAS进行替换加锁
  5. 加锁成功后则将当前线程设置为获取锁的线程
  6. 锁状态不为0,有线程在执行,如果当前线程已经是获取锁的线程了,即锁重入。
  7. 将锁状态+1,表示内部又获取一次
  8. 用CAS替换为加锁后的状态

image-20230913120423008

公平锁

通过FairSync来实现,重写了 tryAcquire方法来获取锁

protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();	// 1
    int c = getState();							  // 2	
    if (c == 0) {								 // 3
        if (!hasQueuedPredecessors() &&				// 4
            compareAndSetState(0, acquires)) {		// 5
            setExclusiveOwnerThread(current);		// 6
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {	// 7
        int nextc = c + acquires;					 // 8
        if (nextc < 0)
            throw new Error("Maximum lock count exceeded");
        setState(nextc);						  // 9
        return true;
    }
    return false;
}
  1. 获取要拿锁的那个线程
  2. 获取此时锁的状态
  3. 如果此时处于无锁状态
  4. 判断此时等待队列队头是否在执行,或者队列有在等待的任务。
  5. 如果等待队列此时为空或者队头没有下一个元素或者下一个元素就是自己,会尝试去将锁状态用CAS进行修改
  6. CAS修改成功会将执行线程设置为自己
  7. 如果锁状态不为0,即有线程在占用,检查是否此时线程就是获得锁的线程
  8. 将锁状态加1,代表锁重入了
  9. 将锁状态更新。

image-20230913120627334

Semaphore信号量

Semaphore继承了AQS,实现了它的共享锁模板方法。把初始state设置为允许的线程数量,每当一个线程获取锁时会判断state是否大于0,大于0则可以获取锁,小于等于0则要进行等待自旋。

CountDownLatch 倒计时器

CountDownLatch 将state设置为count数,可以每次执行 countDown方法会用CAS让state减一,实质时释放掉一个锁,当state为0时会完全释放掉锁,让调用wait方法阻塞的线程进行执行。wait实质就是尝试获取锁,没有获取成功则进入等待状态。

CyclicBarrier循环栅栏

与CountDownLatch类似,可以实现线程间的等待技术,但是功能更加强大。

让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时才会放开,所有被阻塞的线程继续执行。

posted @   墨鱼yyyl  阅读(11)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示