Java并发-深入理解Semaphore(信号量)之源码解析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_22271479/article/details/85058807

深入理解Semaphore(信号量)

Semaphore借助AQS

  • Sync 继承 AbstractQueuedSynchronizer(AQS同步器)
  • NonfairSync Sync的非公平实现
  • FairSync Sync的公平实现

为什么没有实现Lock接口?

  • 因为,lock和unlock没有参数,无法达到此效果

套路(同ReentrantLock)

  • AQS操作,是集成AQS类作为静态内部类
  • Sync默认是非公平的实现
  • NonfairSync 非公平同步器
  • FairSync 公平同步器

Semaphore的特性

  • Semaphore是一个共享同步队列
  • Semaphore主要是控住同一时间运行的线程数
  • state标识当前运行的线程数
  • 是可以响应中断的

源码分析

构造

Semaphore构造

    //默认识非公平同步队列
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

Semaphore.Sync构造

        //permits表示,限制限号量,此时state==permits
        Sync(int permits) {
            setState(permits);
        }

aquire()方法

    public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        //调用AQS的acquireSharedInterruptibly
        sync.acquireSharedInterruptibly(permits);
    }
     
    //AQS
    public final void acquireSharedInterruptibly(int arg)
                throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            // 这里调用Semaphore的tryAcquireShared方法,如果<0,标识不能获取该资源锁,就会入队
            if (tryAcquireShared(arg) < 0)
                //可以被中断的入队操作
                doAcquireSharedInterruptibly(arg);
    }
    //非公平的tryAcquireShared方法调用父类的nonfairTryAcquireShared方法
    final int nonfairTryAcquireShared(int acquires) {
                for (;;) {
                    int available = getState();
                    int remaining = available - acquires;
                    //这里remaining标识剩余的信号量
                    //remaining小于0会直接返回,在AQS只有>0的返回值才能获取资源锁
                    if (remaining < 0 ||
                        //CAS操作,对state进行赋值,成功设置state,此时信号量>0,即可获取资源锁
                        compareAndSetState(available, remaining))
                        return remaining;
                }
    }
    
    //公平同步器的tryAcquireShared方法
    protected int tryAcquireShared(int acquires) {
                for (;;) {
                    //这里判断是否存在前继节点,存在就不可获取资源锁,能获取资源锁的之能事head节点
                    if (hasQueuedPredecessors())
                        return -1;
                    //同上操作
                    int available = getState();
                    int remaining = available - acquires;
                    if (remaining < 0 ||
                        compareAndSetState(available, remaining))
                        return remaining;
                }
    }
    

release()方法

    //获取的时候,传入的信号值必须和释放的信号值相匹配
    public void release(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.releaseShared(permits);
    }
    
    public final boolean releaseShared(int arg) {
        //首先调用tryReleaseShared,该操作是一个资源操作,只可能返回true
        if (tryReleaseShared(arg)) {
        //进行释放,其实就是讲该节点从同步队列中移除,更新新的head指向的node引用
            doReleaseShared();
            return true;
        }
        return false;
    }
    
    //Syn统一实现了该方法,释放可以公用的
        protected final boolean tryReleaseShared(int releases) {
            for (;;) {
                int current = getState();
                int next = current + releases;
                if (next < current) // overflow
                    throw new Error("Maximum permit count exceeded");
                //CAS操作,更新state的值
                if (compareAndSetState(current, next))
                    return true;
            }
        }

Demo

总会是maxCount个线程一起执行,这里信号量规定了5个,而每次线程需要信号为1,那么就表示,该信号量支持5
个线程同时执行任务。也支持每个线程需要的信号不同,资源一定的情况下,每个线程消耗不一样,维持系统稳定。

/**
 * describe:
 * E-mail:[email protected]  date:2018/12/17
 *
 * @Since 0.0.1
 */
public class SemaphoreTest {
    //信号量的permits
    private final int maxCount;
    private final Semaphore semaphore;

    public SemaphoreTest(int maxCount) {
        this.maxCount = maxCount;
        //默认是nofair
        this.semaphore = new Semaphore(maxCount);
    }

    public void add() {
        try {
            //获取到信号量
            semaphore.acquire();
            //操作
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();
        }
    }


}

class A extends Thread {
    SemaphoreTest semaphoreTest;

    public A(SemaphoreTest semaphoreTest) {
        this.semaphoreTest = semaphoreTest;
    }

    @Override
    public void run() {
        semaphoreTest.add();
        System.out.println("add:");
    }
}



class Test {
    public static void main(String[] args) {
        SemaphoreTest semaphoreTest = new SemaphoreTest(5);
        for (int i = 0; i < 10; i++) {
            A a = new A(semaphoreTest);
            a.start();
        }
    }
}

GitHub主页

猜你喜欢

转载自blog.csdn.net/qq_22271479/article/details/85058807