Java并发编程之Semaphore(二)

一.介绍
Semaphore是一种在多线程环境下使用的设施,该设施负责协调各个线程,以保证它们能够正确、合理的使用公共资源的设施,也是操作系统中用于控制进程同步互斥的量。Semaphore是一种计数信号量,用于管理一组资源,内部是基于AQS的共享模式。它相当于给线程规定一个量从而控制允许活动的线程数。
二.工作原理
Semaphore是计数信号量。Semaphore管理一系列许可证。每个acquire方法阻塞,直到有一个许可证可以获得然后拿走一个许可证;每个release方法增加一个许可证,这可能会释放一个阻塞的acquire方法。然而,其实并没有实际的许可证这个对象,Semaphore只是维持了一个可获得许可证的数量。

Semaphore经常用于限制获取某种资源的线程数量。
Semaphore主要方法:
Semaphore(int permits):构造方法,创建具有给定许可数的计数信号量并设置为非公平信号量。
Semaphore(int permits,boolean fair):构造方法,当fair等于true时,创建具有给定许可数的计数信号量并设置为公平信号量。
void acquire():从此信号量获取一个许可前线程将一直阻塞。相当于一辆车占了一个车位。
void acquire(int n):从此信号量获取给定数目许可,在提供这些许可前一直将线程阻塞。比如n=2,就相当于一辆车占了两个车位。
void release():释放一个许可,将其返回给信号量。就如同车开走返回一个车位。
void release(int n):释放n个许可。
int availablePermits():当前可用的许可数。
三.示例
下面举个例子,比如一个停车场可以停放一些车辆,如果停放满了那后面的车就不能进来,如果没满则后面的车可以继续进来,如果满了,后面的车只能等待直到有空余车位:
例子:一辆车占用一个线程,并用Semphore类创建对象从而初始化信号量,控制可活动的线程数,也就是信号量控制车位的剩余量,

1.当信号量为1时,具体代码如下:
  private static final Semaphore semaphore=new Semaphore(1);
        public static class partCarRunable implements Runnable {
        private final String carName;
        public partCarRunable(String name){
            this.carName=name;
        }
        @Override
        public void run() {
            try {
                semaphore.acquire();
                System.out.println("线程名称:"+Thread.currentThread().getName()+",车类型:"+carName+",当前可用停车位:"+semaphore.availablePermits()+",当前时间为:"+System.currentTimeMillis());
                semaphore.release();
                System.out.println("离开:"+Thread.currentThread().getName()+","+carName+"已离场,当前可用停车位:"+semaphore.availablePermits()+",当前时间为:"+System.currentTimeMillis());
            }
            catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        final String[] carName= {"大众","奔驰","宝马","北京现代","哈佛"};
        ExecutorService executorService = newCachedThreadPool();//线程池
        for(int i=0;i<carName.length;i++) {
            partCarRunable carRunable = new partCarRunable(carName[i]);
            executorService.execute(carRunable);
        }
    }
}

结果

线程名称:pool-1-thread-1,车类型:大众,当前可用停车位:0,当前时间为:1542180562936
大众已离场,当前可用停车位:1,当前时间为:1542180562937
线程名称:pool-1-thread-2,车类型:奔驰,当前可用停车位:0,当前时间为:1542180562937
奔驰已离场,当前可用停车位:1,当前时间为:1542180562938
线程名称:pool-1-thread-3,车类型:宝马,当前可用停车位:0,当前时间为:1542180562938
宝马已离场,当前可用停车位:1,当前时间为:1542180562938
线程名称:pool-1-thread-4,车类型:北京现代,当前可用停车位:0,当前时间为:1542180562938
北京现代已离场,当前可用停车位:1,当前时间为:1542180562938
线程名称:pool-1-thread-5,车类型:哈佛,当前可用停车位:0,当前时间为:1542180562939
哈佛已离场,当前可用停车位:1,当前时间为:1542180562939

说明当信号量为1时候,则同一时刻只占用一个停车位,只能等它释放之后才能进来后续的车辆进场,如果当信号量没释放,则后面的车辆进场将一直处于等待状态.

2.如果信号量为2的非公平性信号量时,即
private static final Semaphore semaphore=new Semaphore(2);

则看结果

线程名称:pool-1-thread-1,车类型:大众,当前可用停车位:1,当前时间为:1542181505223
离开:pool-1-thread-1,大众已离场,当前可用停车位:2,当前时间为:1542181505224
线程名称:pool-1-thread-2,车类型:奔驰,当前可用停车位:1,当前时间为:1542181505225
线程名称:pool-1-thread-3,车类型:宝马,当前可用停车位:0,当前时间为:1542181505225
离开:pool-1-thread-3,宝马已离场,当前可用停车位:1,当前时间为:1542181505225
离开:pool-1-thread-2,奔驰已离场,当前可用停车位:2,当前时间为:1542181505225
线程名称:pool-1-thread-4,车类型:北京现代,当前可用停车位:1,当前时间为:1542181505226
离开:pool-1-thread-4,北京现代已离场,当前可用停车位:2,当前时间为:1542181505226
线程名称:pool-1-thread-5,车类型:哈佛,当前可用停车位:1,当前时间为:1542181505229
离开:pool-1-thread-5,哈佛已离场,当前可用停车位:2,当前时间为:1542181505229

这是非公平信号量,通过结果,可以看出有两个空余车位时候,同一时刻有两个车辆线程同时进入车库停车,刚开始线程1进入后马上又离开,此时剩余2个车位,后线程2,3车辆进场,此时已无空余车位,线程等待,后线程3,线程2离场,以此类推,非公平性信号量可以看出进入和出去的线程没有先后顺序,有竞争的情况

3.如果信号量为2的公平性信号量时,即
private static final Semaphore semaphore=new Semaphore(2,true);

结果:

线程名称:pool-1-thread-1,车类型:大众,当前可用停车位:1,当前时间为:1542181386772
离开:pool-1-thread-1,大众已离场,当前可用停车位:2,当前时间为:1542181386772
线程名称:pool-1-thread-2,车类型:奔驰,当前可用停车位:1,当前时间为:1542181386774
离开:pool-1-thread-2,奔驰已离场,当前可用停车位:2,当前时间为:1542181386774
线程名称:pool-1-thread-3,车类型:宝马,当前可用停车位:1,当前时间为:1542181386774
离开:pool-1-thread-3,宝马已离场,当前可用停车位:1,当前时间为:1542181386774
线程名称:pool-1-thread-4,车类型:北京现代,当前可用停车位:0,当前时间为:1542181386774
离开:pool-1-thread-4,北京现代已离场,当前可用停车位:2,当前时间为:1542181386774
线程名称:pool-1-thread-5,车类型:哈佛,当前可用停车位:1,当前时间为:1542181386774
离开:pool-1-thread-5,哈佛已离场,当前可用停车位:2,当前时间为:1542181386774

通过结果可以看出,当有空余信号量时,线程进入的顺序保持公平性,按顺序进场,离场的也按照进场的顺序出场.
四.总结
Semaphore主要用于控制当前活动线程数目,就如同停车场系统一般,而Semaphore则相当于看守的人,用于控制总共允许停车的停车位的个数,而对于每辆车来说就如同一个线程,线程需要通过acquire()方法获取许可,而release()释放许可。如果许可数达到最大活动数,那么调用acquire()之后,便进入等待队列,等待已获得许可的线程释放许可,从而使得多线程能够合理的运行。

猜你喜欢

转载自blog.csdn.net/u010520146/article/details/84067915
今日推荐