2020-02-06 2.4 信号量 Samaphore

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

2.4 信号量(对象Samaphore

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

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

信号量类提供如下方法:

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

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

/**
 * @author xx
     * 2020年2月6日 上午10:44:00 xx添加此方法
 */
public class ConnectionPool {
    
    /**
     * 控制连接池大小的信号量
     */
    private final Semaphore sem;
    
    /**
     * 获取连接的超时时长
     */
    private int fetchTimeOut;
    
    /**
     * 空闲连接的容器
     */
    private LinkedList freeConnections;
    
    /**
     * 正在使用的连接的容器
     */
    private LinkedList busyConnections;
    
    /**
     * 
     * 构造函数
     * @param capacity 连接池大小
     * @param fetchTimeOut 连接池获取连接超时时长(s)
     */
    public ConnectionPool(int capacity, int fetchTimeOut) {
        this.sem = new Semaphore(capacity);
        this.fetchTimeOut = fetchTimeOut;
        this.freeConnections = new LinkedList();
        this.busyConnections = new LinkedList();
    }
    
    /**
     * 从连接池获取一个连接
     * 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)