源码分析-Semaphor

Posted 千念飞羽

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了源码分析-Semaphor相关的知识,希望对你有一定的参考价值。

semaphore

java中的Semaphore主要用来限制线程的数量。而不是用来限制资源的访问。Semaphore所拥有的集是非常抽象的集合。所以说Semaphore在获取和是否的过程中不会持有特定对象的锁。

即使排除java的语义概念,锁和信号量,虽然都是基于等待唤醒机制,但是也是不同的同步组件。虽然锁可以用来做同步器,同步器可以用来做锁,但是信号量并没有所有者的概念。由于没有所有者的概念,信号量一般用来限制线程数量,而锁用来控制资源访问。这样有什么好处,一个例子就是在死锁恢复的过程中,如果你用的是锁,那必须又拥有这个锁的拥有者去释放,如果你用的是信号量就不需要拥有者去释放这个线程。比如你可以设定在线程终止时自动释放。这样就不会绑定特定的拥有者。

主要方法

从结构上说Semaphore的构成比较简单,就是内部有三个类,一个Sync继承自AQS。这个Sync是一个抽象类,下面继承了2个类分别是NonfairSync和FairSync两个具体的子类,在构造的时候选择使用哪一个。
只要搞懂AQS,Semaphore的内容很简单。
Semaphore的方法基本上没有什么可以说的,这里就看一下这三个类的主要方法就可以了:

Sync

    abstract static class Sync extends AbstractQueuedSynchronizer 
        private static final long serialVersionUID = 1192457210091910933L;

        Sync(int permits) 
            setState(permits);
        

        final int getPermits() 
            return getState();
        

        final int nonfairTryAcquireShared(int acquires) //这里主要是非公平锁的实现方式,但是我有一点不太明白为什么要写在Sync并且用final,如果我来写的话我会放在NonfairTryAcquireShared中间。这个也是通常实现获取非公平共享锁的典型形式。
            for (;;) 
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            
        

        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");
                if (compareAndSetState(current, next))
                    return true;
            
        

        final void reducePermits(int reductions) //这个方法主要是控制运行线程数量的。
            for (;;) 
                int current = getState();
                int next = current - reductions;
                if (next > current) // underflow
                    throw new Error("Permit count underflow");
                if (compareAndSetState(current, next))
                    return;
            
        

        final int drainPermits() 
            for (;;) 
                int current = getState();
                if (current == 0 || compareAndSetState(current, 0))
                    return current;
            
        
    

NonfairSync

非公平锁的实现比较简单只要委托给tryAcquireShared就行

    static final class NonfairSync extends Sync 
        private static final long serialVersionUID = -2694183684443567898L;

        NonfairSync(int permits) 
            super(permits);
        

        protected int tryAcquireShared(int acquires) 
            return nonfairTryAcquireShared(acquires);
        
    

FairSync

公平锁的实现

    static final class FairSync extends Sync 
        private static final long serialVersionUID = 2014338818796000944L;

        FairSync(int permits) 
            super(permits);
        

        protected int tryAcquireShared(int acquires) 
            for (;;) 
                if (hasQueuedPredecessors())//和非公平锁的实现的区别就是这里加了这一条这个是AQS的方法用来判断当前是否有线程排队获取锁。其他内容和非公平锁一致。
                    return -1;
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            
        
    

以上是关于源码分析-Semaphor的主要内容,如果未能解决你的问题,请参考以下文章

ReentrantLock源码分析

ReentrantLock源码分析

ReentrantLock源码分析

jdk源码分析红黑树——插入篇

JDK源码ArrayDeque源码分析

List源码解析之ArrayList源码分析