JUC(2)---Semaphore和AQS

Semaphore意思的信号量,它的作用是控制访问特定资源的线程数量

构造方法

public Semaphore(int permits)

public Semaphore(int permits, boolean fair)

  permits:允许同时访问的线程数量

  fair:是否公平,若true的话,下次执行的会是先进去等待的线程(先入先出)

 

使用

acquire():获取许可执行

release():释放许可,让其他线程获取许可执行。

 

显然这个功能可以用于资源访问控制或者是限流的操作。

 

如下代码每次只会有两个线程执行。

package com.nijunyang.concurrent;

import java.util.concurrent.Semaphore;

/**
 * Description:
 * Created by nijunyang on 2020/5/13 23:31
 */
public class SemaphoreTest {
    Semaphore semaphore;

    public SemaphoreTest(Semaphore semaphore) {
        this.semaphore = semaphore;
    }

    public static void main(String[] args) {
        SemaphoreTest semaphoreTest = new SemaphoreTest(new Semaphore(2, true));
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                try {
                    semaphoreTest.test();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "线程" + i);
            thread.start();
        }
        System.out.println("线程创建完毕.");
    }

    public void test() throws InterruptedException {
        semaphore.acquire();
        System.out.println(Thread.currentThread().getName() + "执行.");
        Thread.sleep(4000);
        semaphore.release();
    }
}

 

原理

进入Semaphore的代码一看,又见到AQS,前面ReentrantLock中用到的是独占模式,Semaphore中就是共享模式了。和ReentrantLock如出一辙,内部类Sync继承了AbstractQueuedSynchronizer,同时有两个子类实现一个公平FairSync,另一个非公平NonfairSync

构造方法传入的permits,最终会赋值到AbstractQueuedSynchronizerstate字段,这个字段的ReentrantLock中是用来计算锁重入的。但是在Semaphore里面字段是用来控制资源访问数量的。

 

1.acquire方法获取的许可的时候 先去扣减,将state的值-1,如果结果不小于0,就通过CAS操作修改state的值,最后返回当前剩余许可

 

 

 2. 如果返回的许可剩余数量小于0 就执行doAcquireSharedInterruptibly方法,将当前线程以共享的模式加入到队列中去

 

 

3. 拿到前驱结点,根据结点的几个状态去判断前驱结点是否是取消或者其他状态,如果取消状态就剔除出去

 

 

 

4.release方法 释放许可  CAS操作将state的值+1

 

 5.设置成功了执行doReleaseShared方法,去唤醒队列中等待的线程,获取到许可执行

 

 

 

posted @ 2020-05-14 00:20  白露非霜  阅读(341)  评论(0编辑  收藏  举报
访问量