信号量Semaphore

信号量Semaphore


信号量Semaphore是一个控制访问多个共享资源的计数器,和CountDownLatch一样,其本质上是一个“共享锁”。

Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。

信号量Semaphore是一个非负整数(>=1)。当一个线程想要访问某个共享资源时,它必须要先获取Semaphore,当Semaphore >0时,获取该资源并使Semaphore – 1。如果Semaphore值 = 0,则表示全部的共享资源已经被其他线程全部占用,线程必须要等待其他线程释放资源。当线程释放资源时,Semaphore则+1。

实现

其内部也是通过队列同步器实现。

abstract static class Sync extends AbstractQueuedSynchronizer

构造函数

也分为公平的信号量和不公平的信号量,其中默认的为不公平的。

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

主要的公共方法

//获得一个访问许可,如果没有可用资源或者被中断,则阻塞
public void acquire() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}
//对中断不敏感
public void acquireUninterruptibly() {
    sync.acquireShared(1);
}
//再被调用的时候有资源则获取,否则返回false
public boolean tryAcquire() {
    return sync.nonfairTryAcquireShared(1) >= 0;
}
//在规定时间内且未被中断
public boolean tryAcquire(long timeout, TimeUnit unit)
    throws InterruptedException {
    return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
//释放一个资源
public void release() {
    sync.releaseShared(1);
}
//返回可用的资源数
public int availablePermits() {
    return sync.getPermits();
}
//获得并返回所有可以获得的资源数
public int drainPermits() {
    return sync.drainPermits();
}
。。。
还有三个方法就不写了

使用示例

火车站有五个停靠点,有七辆,每辆火车停2秒

package my.syn;

import java.util.concurrent.Semaphore;

/**
 * @ClassName: MyStation
 * @author: Yang.X.P
 * @date: 2018-09-18 09:22
 **/
public class MyStation {
    static Semaphore semaphore = new Semaphore(5);

    public static void main(String[] args) {
        Train train = new Train();
        for (int i = 0; i < 7; i++) {
            Thread trainThread = new Thread(train);
            trainThread.start();
        }
    }
}

class Train implements Runnable {

    @Override
    public void run() {
        if(MyStation.semaphore.availablePermits() ==0) {
            System.out.println(Thread.currentThread().getName()+"火车暂无可停靠点,正在等待" );
        }
        try {
            MyStation.semaphore.acquire();
            System.out.println(Thread.currentThread().getName()+"火车进站停2秒" );
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName()+"火车开出停靠点" );
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        MyStation.semaphore.release();
    }
}

参考资料:

http://cmsblogs.com/?p=2263

posted @ 2018-09-25 20:09  一把水果刀  阅读(277)  评论(0编辑  收藏  举报