美文网首页并发和多线程
2020-02-06 2.4 信号量 Samaphore

2020-02-06 2.4 信号量 Samaphore

作者: FredWorks | 来源:发表于2020-02-06 10:12 被阅读0次

    本文是Java线程安全和并发编程知识总结的一部分。

    2.4 信号量(对象Samaphore

    信号量是用来控制并发执行某个操作的线程数量的同步辅助工具。锁确保每个资源或同步块只能被一个线程访问(读写锁允许多个线程读,一个线程写);而信号量允许控制最多允许多少个线程并发访问。

    信号量需要在构建时指定访问许可的数目。二元信号量(只有1个访问许可的信号量)相当于一个不可重入锁;因为只要有一个操作申请到了信号量,那么下个操作申请时必然失败。

    信号量类提供如下方法:

    • acquire: 申请一个访问许可的一系列重载方法和类似方法,如果没有许可,则阻塞当前线程直到有许可为止。
    • tryAcquire: 申请一个访问许可的一系列重载方法;如果没有许可,则返回false,否则返回true。
    • release: 释放已申请的访问许可的一系列重载方法。

    下面通过使用信号量还改写 条件锁 一章中的连接池例子来说明如何使用信号量:

    /**
     * @author xx
         * 2020年2月6日 上午10:44:00 xx添加此方法
     */
    public class ConnectionPool<T> {
        
        /**
         * 控制连接池大小的信号量
         */
        private final Semaphore sem;
        
        /**
         * 获取连接的超时时长
         */
        private int fetchTimeOut;
        
        /**
         * 空闲连接的容器
         */
        private LinkedList<T> freeConnections;
        
        /**
         * 正在使用的连接的容器
         */
        private LinkedList<T> busyConnections;
        
        /**
         * 
         * 构造函数
         * @param capacity 连接池大小
         * @param fetchTimeOut 连接池获取连接超时时长(s)
         */
        public ConnectionPool(int capacity, int fetchTimeOut) {
            this.sem = new Semaphore(capacity);
            this.fetchTimeOut = fetchTimeOut;
            this.freeConnections = new LinkedList<T>();
            this.busyConnections = new LinkedList<T>();
        }
        
        /**
         * 从连接池获取一个连接
         * 2020年2月6日 上午10:44:00 xx添加此方法
         */
        public T fetchConnectioin(int index) {
            // 如果没有空闲连接,则当前线程挂起等待有空闲连接或超时
            try {
                this.sem.tryAcquire(this.fetchTimeOut, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                throw new RuntimeException("等待空闲连接时线程中断异常", e);
            }
            
            // 独立中监控空闲连接数并决定是否需要新增缓存的连接。
            
            T element = this.freeConnections.remove(this.freeConnections.size() - 1);
            this.busyConnections.add(element);
            
            return element;
        }
        
        /**
         * 将连接释放会连接池
         * 2020年2月6日 上午10:44:00 xx添加此方法
         */
        public void releaseConnection(T connection) {
            if (this.busyConnections.remove(connection)) {
                this.freeConnections.add(connection);
                this.sem.release();
            }
        }
    }
    

    信号量使用时,需注意如下问题:

    • 信号量构建完毕后,是无法修改许可数的。
    • 信号量并不和线程绑定。它只关注颁发了多少许可,是否有释放许可,但并不关心释放许可的是否当初申请需求的那个线程。

    相关文章

      网友评论

        本文标题:2020-02-06 2.4 信号量 Samaphore

        本文链接:https://www.haomeiwen.com/subject/hheyxhtx.html