Semaphore源码讲解

Semaphore称为计数信号量,当线程来访问资源的时候,只有获得许可才可以成功来访问资源.

类继承关系

public class Semaphore implements java.io.Serializable {
}

Semaphore接口只实现了一个序列化接口.可以进行序列化.

内部类

abstract static class Sync extends AbstractQueuedSynchronizer {
}


static final class NonfairSync extends Sync {
}

tatic final class FairSync extends Sync {
}

类内部总共存在Sync、NonfairSync、FairSync三个类,NonfairSync与FairSync类继承自Sync类,Sync类继承自AbstractQueuedSynchronizer抽象类。下面挨个分析实现类的细节.

内部类 - 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) {

            //循环.
            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;
            }
        }
    }

Sync类存在如下方法和作用如下.

内部类 - NonfairSync类

 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);
        }
    }

从源码tryAcquireShared方法可知,最终会调用父类的非公平nonfairTryAcquireShared方法获取许可.

内部类 - 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()) //判断是否有其他节点.并且判断是不是当前节点线程.
                    return -1;
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
    }

从tryAcquireShared方法的源码可知,它使用公平策略来获取资源,它会判断同步队列中是否存在其他的等待节点.依次获取许可.

类的属性

public class Semaphore implements java.io.Serializable {
    // 版本号
    private static final long serialVersionUID = -3222578661600680210L;
    // 属性
    private final Sync sync;
}

Semaphore自身只有两个属性,最重要的是sync属性,基于Semaphore对象的操作绝大多数都转移到了对sync的操作.

类的构造函数

public Semaphore(int permits) {
    sync = new NonfairSync(permits);
}

该构造函数会创建具有给定的许可数和非公平的公平设置的Semaphore.

public Semaphore(int permits, boolean fair) {
    sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}

该构造函数会创建具有给定的许可数和给定的公平设置的Semaphore.

核心函数 - acquire函数

从信号量获取一个(多个)许可,在提供一个许可前一直将线程阻塞,或者线程被中断.源码如下.

public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

该方法中将会调用Sync对象的acquireSharedInterruptibly(从AQS继承而来的方法)方法.acquireSharedInterruptibly找Semaphore实现,具体可以参考CountDownLatch.

核心函数 - release函数

方法释放一个(多个)许可,将其返回给信号量,源码如下.

public void release() {
        sync.releaseShared(1);
    }

该方法中将会调用Sync对象的releaseShared(从AQS继承而来的方法)方法.releaseShared找Semaphore实现,具体可以参考CountDownLatch.

Semaphore示例

class MyThread3 extends Thread {
    private Semaphore semaphore;
    
    public MyThread3(String name, Semaphore semaphore) {
        super(name);
        this.semaphore = semaphore;
    }
    
    @Override
    public void run() {        
        int count = 3;
        System.out.println(Thread.currentThread().getName() + " trying to acquire");
        try {
            semaphore.acquire(count);
            System.out.println(Thread.currentThread().getName() + " acquire successfully");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release(count);
            System.out.println(Thread.currentThread().getName() + " release successfully");
        }
    }
}

public class SemaphoreDemo {
    public final static int SEM_SIZE = 10;
    
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(SEM_SIZE);
        MyThread3 t1 = new MyThread3("t1", semaphore);
        MyThread3 t2 = new MyThread3("t2", semaphore);
        t1.start();
        t2.start();
        int permits = 5;
        System.out.println(Thread.currentThread().getName() + " trying to acquire");
        try {
            semaphore.acquire(permits);
            System.out.println(Thread.currentThread().getName() + " acquire successfully");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();
            System.out.println(Thread.currentThread().getName() + " release successfully");
        }      
    }
}

执行结果.

生成一个信号量,信号量有10个许可,然后主线程和t1 t2依次获取.可能存在如下情况.

 如上图所示,首先,main线程执行acquire操作,并且成功获得许可,之后t1线程执行acquire操作,成功获得许可,之后t2执行acquire操作,由于此时许可数量不够,t2线程将会阻塞,直到许可可用。之后t1线程释放许可,main线程释放许可,此时的许可数量可以满足t2线程的要求,所以,此时t2线程会成功获得许可运行,t2运行完成后释放许可.

main线程执行semaphore.acquire操作。主要的函数调用如下图所示

可以看到只是AQS的state变为了5,main线程并没有被阻塞,可以继续运行.

t1线程执行semaphore.acquire操作。主要的函数调用如下图所示

可以看到只是AQS的state变为了2,t1线程并没有被阻塞,可以继续运行 .

t2线程执行semaphore.acquire操作。主要的函数调用如下图所示

t2线程获取许可不会成功,之后会导致其被禁止运行,值得注意的是,AQS的state还是为2.

t1执行semaphore.release操作。主要的函数调用如下图所示

 

t2线程将会被unpark,并且AQS的state为5,t2获取cpu资源后可以继续运行 

main线程执行semaphore.release操作。主要的函数调用如下图所示

t2线程还会被unpark,但是不会产生影响,此时,只要t2线程获得CPU资源就可以运行了。此时,AQS的state为10。 

t2获取CPU资源,继续运行,此时t2需要恢复现场,回到parkAndCheckInterrupt函数中,也是在should继续运行。主要的函数调用如下图所示。

可以看到,Sync queue中只有一个结点,头节点与尾节点都指向该结点,在setHeadAndPropagate的函数中会设置头节点并且会unpark队列中的其他结点。

t2线程执行semaphore.release操作。主要的函数调用如下图所示

 

t2线程经过release后,此时信号量的许可又变为10个了,此时Sync queue中的结点还是没有变化 .

是否真正的坚持过一件事.不管风吹雨打.是热爱,还是心里的不甘,还是因为说出口的时候太年少. 不管如何,如果在坚持,那么坚持下去,虽然不知道结果如何,但是能肯定的是你真的很了不起.送给那些始终在心里还有一丝丝倔强的你们,包括我自己.国庆快乐,共勉快乐.

如果大家喜欢我的分享的话.可以关注下我的微信公众号

心有九月星辰

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值