zoukankan      html  css  js  c++  java
  • Semaphore 信号量

    一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。

    但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。拿到信号量的线程可以进入代码,否则就等待。通过acquire()和release()获取和释放访问许可。

     1 acquire
     2 public void acquire()
     3              throws InterruptedException
     4 从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。获取一个许可(如果提供了一个)并立即返回,将可用的许可数减 1 5 如果没有可用的许可,则在发生以下两种情况之一前,禁止将当前线程用于线程安排目的并使其处于休眠状态:
     6 某些其他线程调用此信号量的 release() 方法,并且当前线程是下一个要被分配许可的线程;或者
     7 其他某些线程中断当前线程。
     8 如果当前线程:
     9 被此方法将其已中断状态设置为 on ;或者
    10 在等待许可时被中断。
    11 则抛出 InterruptedException,并且清除当前线程的已中断状态。 
    12 抛出:
    13 InterruptedException - 如果当前线程被中断
    1 release
    2 public void release()
    3 释放一个许可,将其返回给信号量。释放一个许可,将可用的许可数增加 1。如果任意线程试图获取许可,则选中一个线程并将刚刚释放的许可给予它。然后针对线程安排目的启用(或再启用)该线程。
    4 不要求释放许可的线程必须通过调用 acquire() 来获取许可。通过应用程序中的编程约定来建立信号量的正确用法。

    下面的例子只允许5个线程同时进入执行acquire()和release()之间的代码:

     1 public class SemaphoreTest {
     2 
     3      public static void main(String[] args) {  
     4         // 线程池 
     5         ExecutorService exec = Executors.newCachedThreadPool();  
     6         // 只能5个线程同时访问 
     7         final Semaphore semp = new Semaphore(5);  
     8         // 模拟20个客户端访问 
     9         for (int index = 0; index < 20; index++) {
    10             final int NO = index;  
    11             Runnable run = new Runnable() {  
    12                 public void run() {  
    13                     try {  
    14                         // 获取许可 
    15                         semp.acquire();  
    16                         System.out.println("Accessing: " + NO);  
    17                         Thread.sleep((long) (Math.random() * 10000));  
    18                         // 访问完后,释放 ,如果屏蔽下面的语句,则在控制台只能打印5条记录,之后线程一直阻塞
    19                         semp.release();  
    20                     } catch (InterruptedException e) {  
    21                     }  
    22                 }  
    23             };  
    24             exec.execute(run);  
    25         }  
    26         // 退出线程池 
    27         exec.shutdown();  
    28     }  
    29 }

     比较形象的解释:

    Semaphore分为单值和多值两种,前者只能被一个线程获得,后者可以被若干个线程获得。

    Semaphore实现的功能就类似厕所有5个坑,假如有10个人要上厕所,那么同时只能有多少个人去上厕所呢?同时只能有5个人能够占用,当5个人中 的任何一个人让开后,其中等待的另外5个人中又有一个人可以占用了。另外等待的5个人中可以是随机获得优先机会,也可以是按照先来后到的顺序获得机会,这取决于构造Semaphore对象时传入的参数选项。单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,这可应用于死锁恢复的一些场合。

    再以一个停车场运作为例。为了简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆不受阻碍的进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入一辆,如果又离开两辆,则又可以放入两辆,如此往复。

    在这个停车场系统中,车位是公共资源,每辆车好比一个线程,看门人起的就是信号量的作用。

    更进一步,信号量的特性如下:信号量是一个非负整数(车位数),所有通过它的线程(车辆)都会将该整数减一(使用资源),当该整数值为零时,所有试图通过它的线程都将处于等待状态。在信号量上我们定义两种操作: Wait(等待) 和 Release(释放)。 当一个线程调用Wait(等待)操作时,它要么通过然后将信号量减一,要么一直等下去,直到信号量大于一或超时。Release(释放)实际上是在信号量上执行加操作,对应于车辆离开停车场,该操作之所以叫做“释放”是因为加操作实际上是释放了由信号量守护的资源。

    Semaphore(int permits, boolean fair)
    //创建具有给定的许可数和给定的公平设置的Semaphore。

    还可以设置该信号量是否采用公平模式,如果以公平方式执行,则线程将会按到达的顺序(FIFO)执行,如果是非公平,则可以后请求的有可能排在队列的头部。

  • 相关阅读:
    spring-boot、spring-data-jpa整合
    Executors中的几种线程调用方式
    通过BeanFactoryPostProcessor来获取bean
    spring、spring-data-redis整合使用
    java.io几种读写文件的方式
    springmvc+quartz简单实现定时调度
    httpclient跳过https请求的验证
    Gson的几种使用方式
    httpclient的几种请求URL的方式
    【转】文件各种上传,离不开的表单
  • 原文地址:https://www.cnblogs.com/wihainan/p/7541965.html
Copyright © 2011-2022 走看看