Semaphore

person-walking-on-pathway-3348363.jpg

简介:

多线程一直是Java中的一个难点和重点,里面涉及到的东西很多,今天我们要介绍的就是Semaphore(信号量),可能很多人对它不太熟悉,用到的概率不是很大。不过,在Java的世界里,任何对象的存在,都有它独特的意义。首先,这个类也是在java.util.concurrent这个并发包下面的,也是用来控制多线程访问的。一般是用来限制访问某一资源的线程数的,不像synchronized一次只允许一个线程访问同一个资源,Semaphore可以灵活的定义访问资源的数量,感觉和令牌桶的算法差不多。

类图:

Semaphore类图.png

举例:

接下来的代码例子其实是Semaphore类注释上面的,拿过来一起学习一下。

    private static final int MAX_AVAILABLE = 2;//the initial number of permits available(可同时允许的线程数量)
    private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);//true:公平锁
    protected Object[] items = {"a","b","c","d","e","f","g"};//资源
    protected boolean[] used = new boolean[MAX_AVAILABLE];

    public Object getItem() throws InterruptedException {//线程获取资源的入口,在获取资源之前,首先要过acquire这一关
        available.acquire();
        return getNextAvailableItem();
    }

    public void putItem(Object x) {//用完之后,归还permits,这样其他的线程,才可以继续用
        if (markAsUnused(x))
            available.release();
    }

    protected synchronized Object getNextAvailableItem() {//synchronized修饰的方法,因为有可能会有多个线程,所以要保证线程安全
        for (int i = 0; i < MAX_AVAILABLE; ++i) {
            if (!used[i]) {
                used[i] = true;
                return items[i];
            }
        }
        return null;
    }

大家可以自己在这个例子基础上测试一下,体会一下其中的思想。

源码:

源码简单分析一下,其实Semaphore的底层依靠的还是强大的AQS,就像上面的类图一样,在AQS的基础上,可以自定义自己的逻辑,比如,把permit放在state里面。

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

这个类其实用到了模板模式的思想,把一些公共的方法放在抽象类里面,然后下面一个NonfairSync,一个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;
            }
        }
    }
    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);
        }
    }

总结:

Java里面的知识,说实话需要学习的东西确实非常多,需要花费很多精力。但同时,随着你看源码看的越多,会慢慢的发现,好多东西的设计思想都是类似的,并且写的代码,都不是很复杂,仅仅是一层套一层,把人套糊涂啦。所以在学习知识的时候,就像一位大神说过的,最好先看官方文档,先了解其整体脉络,然后再带着问题去看源码,去寻找答案,这样效率会很高。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容