Semaphore信号量

Semaphore,等待指定数量的线程完成任务即可

Semaphore信号量
public class A {

    private static SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    // 同步关键类,构造方法传入的数字是多少,则同一个时刻,只运行多少个进程同时运行制定代码
    private Semaphore semaphore = new Semaphore(2);

    public static void main(String[] args) throws Exception{
        A a = new A();
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                a.doSomething();
            }).start();
        }
    }


    public void doSomething() {
        try {
            /**
             * 在 semaphore.acquire() 和 semaphore.release()之间的代码,同一时刻只允许制定个数的线程进入,
             * 因为semaphore的构造方法是1,则同一时刻只允许一个线程进入,其他线程只能等待。
             * */
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName() + ": start-" + getFormatTimeStr());
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + ": end-" + getFormatTimeStr());
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static String getFormatTimeStr() {
        return sf.format(new Date());
    }
}
View Code

初始化

  初始化的时候,就是将 permits 设置给 state,标记占用锁标识。state的值就代表当前所剩余的令牌数量。

 Semaphore信号量

acquire()

获取令牌

  在 tryAcquireShared() 里面,第一个线程会先获取到当前的令牌数量,我们初始化的时候是2,remaining = 2-1>0 ,所以走cas操作赋值,等到第三个线程来的时候,则 remaining = 0-1>0,此时第三个线程就没获取到令牌了,走下面的 doAcquireSharedInterruptibly() 方法。

Semaphore信号量

挂起线程

获取到令牌的线程就继续执行它的业务逻辑了,没有获取到令牌的线程就会来到这里。
1. addWaiter(Node.SHARED); 首先创建节点加入阻塞队列
2. node.predecessor(); 获取到上一个节点p,如果上一个节点是头节点,说明自己排在第一个。
3. 如果自己是第一个线程就 tryAcquireShared() 尝试cas获取令牌。(因为可能走到这里时,别人释放了令牌啊)
4. 然后 r>=0 就获取到了令牌,那就把当前线程从对等队列里面摘取出来
5. 如果不是第一个排队的节点,那就在 parkAndCheckInterrupt() 里面通过 park() 操作把自己挂起来,等待其他线程来把它唤醒

Semaphore信号量

release()

释放令牌

  在 tryReleaseShared() 里面将 state 加一,然后cas操作执行成功就去唤醒等待队列中的节点。

Semaphore信号量

唤醒其他节点

1. 判断头节点 h 的状态 Node.SIGNAL 是否需要唤醒后继节点
2. 进行 cas 操作修改状态为初始0
3. unparkSuccessor(h) 唤醒 h.next 节点

Semaphore信号量

 

上一篇:Semaphore 的使用


下一篇:channel实现并发控制