heima并发27---semaphore---261-265

信号量。

信号量是用来限制能访问共享资源的线程上限的。

共享资源有多个,允许访问共享资源,只是希望对线程的上限进行控制。

semaphore是停车场的车位,线程是汽车,剩余的空闲车位。

---261---

代码:

三个许可,用一个少一个。

package cn.itcast.n8;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Semaphore;

import static cn.itcast.n2.util.Sleeper.sleep;

@Slf4j(topic = "c.TestSemaphore")
public class TestSemaphore {
    public static void main(String[] args) {
        // 1. 创建 semaphore 对象
        Semaphore semaphore = new Semaphore(3);
        // 2. 10个线程同时运行
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                try {
                    semaphore.acquire();// 获得许可之后是可以被打断的
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    log.debug("running...");
                    sleep(1);
                    log.debug("end...");
                } finally {
                    semaphore.release();// 释放许可
                }
            }).start();
        }
    }
}

---262---

应用:

限制的只是线程数。

资源数和线程数一样的时候用信号量是比较合适的。

改进数据库的连接池,数据库连接池是一个线程对应一个连接,不能多个线程对应一个数据库连接:

限流是限制连接数。

代码:

之前的代码:

代码:

第一步:在构造函数初始化一下让许可数和资源数是一样的。

第二步:借连接,没有许可就等待即可,相当于wait,进去取肯定会有的因为许可数和连接数是一样的。

第三步:归还许可

---263---

原理:

我们看下构造方法:

继承了同步器。

点进去父类的构造,实际上就是将state赋值给构造方法的state:

同步器继承aqs,构造方法的参数传给了states。

---------------------------------------------------------------------------------------------

构造方法就看完了。

看下线程的获取资源,是可打断的acquire:

点进去:

<0是失败,返回的是剩余的资源数。

点进去这个方法,找到子类:

点进去:

这里里面的逻辑很简答:

先获得当前的许可,减去我要用的,然后cas改为当前的许可-我要用的。

假设许可是0了,此时再进来一个,则为-1,此时就返回的是负数了,则再进入方法。

则进入到这个方法:

这个代码就是加入到等待队列里面:

分析这段代码:

1.首先创建一个节点,加入到队列。

就是把这两个节点都创建好了。

2.看下前驱节点是不是老二,老二就还有资格取竞争锁

3.前驱节点的状态改为-1,然后park住。

在这里改为-1的。

---264---

我们再看下release流程:

调用tryReleaseShare方法。

进入:

看下实现:

进入到这个方法:

此时state为0,说明都用完了。

0+1=1.

cas从0改为1。

不记录线程,只记录state。

---

再翻回来,进入这方法:

流程:

1.首先拿到头节点,看它是不是-1。-1的话就表示有后继的节点需要唤醒,尝试由-1改为0。

2.开始唤醒

3.我们看下阻塞的节点在哪里阻塞着呢

1.在箭头唤醒,看下前驱节点是不是头节点。结果是的,并且自己是老二。

2.再次:

这个把剩余量由1改为0。

3.再次进入if块

4.把自己设置为头节点,原来的节点就不要了。

唤醒后继的共享节点,由于共享节点是连续的,则挨个唤醒的。

但是受到states的限制了,还会进入park。

---265---

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值