Java并发编程(8)-Semaphore信号量解读

版权声明: https://blog.csdn.net/pbrlovejava/article/details/83655580


更多关于Java并发编程的文章请点击这里:Java并发编程实践(0)-目录页


在Java并发编程中,信号量Semaphore类)可视为synchronized的升级,它能控制一个程序中线程的数量,负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。

一、Semaphore信号量

1.1、什么是信号量

以一个停车场是运作为例。为了简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆不受阻碍的进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入一辆,如果又离开两辆,则又可以放入两辆,如此往复。
在这个停车场系统中,车位是公共资源,每辆车好比一个线程,看门人起的就是信号量的作用。
更进一步,信号量的特性如下:信号量是一个非负整数(车位数),所有通过它的线程(车辆)都会将该整数减一(通过它当然是为了使用资源),当该整数值为零时,所有试图通过它的线程都将处于等待状态。在信号量上我们定义两种操作: Wait(等待) 和 Release(释放)。 当一个线程调用Wait(等待)操作时,它要么通过然后将信号量减一,要么一直等下去,直到信号量大于一或超时。Release(释放)实际上是在信号量上执行加操作,对应于车辆离开停车场,该操作之所以叫做“释放”是因为加操作实际上是释放了由信号量守护的资源。
在java中,还可以设置该信号量是否采用公平模式,如果以公平方式执行,则线程将会按到达的顺序(FIFO)执行,如果是非公平,则可以后请求的有可能排在队列的头部
JDK中定义如下:
Semaphore(int permits, boolean fair)
  创建具有给定的许可数和给定的公平设置的Semaphore。 --百度百科

1.2、信号量在并发编程中的作用

在Java并发编程中,信号量Semaphore类)可视为synchronized的升级,它能控制一个程序中线程的数量,负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。

二、Semaphore类简单解读

Semaphore类位于java.util.concurrent并发包之下,它是信号量的具体实现类。

2.1、构造方法解读

(1)、public Semaphore(int permits)
用给定的许可数和非公平的公平设置创建一个 Semaphore,即线程不按照FIFO的方式执行。

参数:
permits - 初始的可用许可数目。此值可能为负数,在这种情况下,必须在授予任何获取前进行释放。

(2)、public Semaphore(int permits, boolean fair)
用给定的许可数和给定的公平设置创建一个 Semaphore,保证线程的执行是FIFO方式的。

参数:
permits - 初始的可用许可数目。此值可能为负数,在这种情况下,必须在授予任何获取前进行释放。
fair - 如果此信号量保证在争用时按先进先出的顺序授予许可,则为 ture,否则为 false。

2.2、常用方法解读

(1)、acquire方法
public void acquire() throws InterruptedException
从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。 获取一个许可(如果提供了一个)并立即返回,将可用的许可数减 1。
如果没有可用的许可,则在发生以下两种情况之一前,禁止将当前线程用于线程安排目的并使其处于休眠状态:

某些其他线程调用此信号量的 release() 方法,并且当前线程是下一个要被分配许可的线程;
②其他某些线程中断当前线程

(2)、tryAcquire方法
public boolean tryAcquire()
仅在调用时此信号量存在一个可用许可,才从信号量获取许可。
获取一个许可(如果提供了一个)并立即返回,其值为 true,将可用的许可数减 1。 如果没有可用的许可,则此方法立即返回并且值为 false。

public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException
如果在给定的等待时间内此信号量有可用的所有许可,并且当前线程未被中断,则从此信号量获取给定数目的许可。
获取给定数目的许可(如果提供了)并立即返回,其值为 true,将可用的许可数减去给定的量。

如果没有足够的可用许可,则在发生以下三种情况之一前,禁止将当前线程用于线程安排目的并使其处于休眠状态:

①其他某些线程调用此信号量的某个释放方法,当前线程是下一个被分配许可的线程,并且可用许可的数目满足此请求;

②其他某些线程中断当前线程;

③ 已超出指定的等待时间。

(3)、availablePermits方法
public int availablePermits()
返回此信号量中当前可用的许可数。 此方法通常用于调试和测试目的。

(4)、release方法
public void release(int permits)
释放给定数目的许可,将其返回到信号量。
释放给定数目的许可,将可用的许可数增加该量。如果任意线程试图获取许可,则选中某个线程并将刚刚释放的许可给予该线程。如果可用许可的数目满足该线程的请求,则针对线程安排目的启用(或再启用)该线程;否则在有足够的可用许可前线程将一直等待。如果满足此线程的请求后仍有可用的许可,则依次将这些许可分配给试图获取许可的其他线程。

三、简单程序解读

@Test
    public void semaphoreTest(){
        Semaphore semaphore = new Semaphore(3);

        ExecutorService executorService = Executors.newFixedThreadPool(2);
        for (int i = 0; i < 5; i++) {
            executorService.execute(new Runnable(){
                Semaphore semaphore1 = semaphore;
                public void run(){

                    try {
                        semaphore1.acquire();//获取信号量,执行程序
                        System.out.println(Thread.currentThread().getName()+"获得信号量,开始执行程序...,剩余信号量:"+semaphore1.availablePermits());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        semaphore1.release();//释放信号量
                        System.out.println("线程"+Thread.currentThread().getName()+"释放信号量,剩余信号量:"+semaphore1.availablePermits());
                    }

                }
            });
        }
    }

在这里插入图片描述如果我们不释放信号量。那么3信号量被消耗完,程序也就是循环到第3次的时候,程序就已经结束了,因为没有信号量,线程也就没有权利执行程序。

		finally {
                       // semaphore1.release();//释放信号量
                        //System.out.println("线程"+Thread.currentThread().getName()+"释放信号量,剩余信号量:"+semaphore1.availablePermits());
                        System.out.println("剩余信号量:"+semaphore1.availablePermits());

                    }

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/pbrlovejava/article/details/83655580