博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java核心知识点学习----线程中的Semaphore学习,公共厕所排队策略
阅读量:5813 次
发布时间:2019-06-18

本文共 4005 字,大约阅读时间需要 13 分钟。

1.什么是Semaphore?

A counting semaphore. Conceptually, a semaphore maintains a set of permits. Each acquire blocks if  necessary until a permit is available, and then takes it. Each release adds a permit, potentially releasing a  blocking acquirer. However, no actual permit objects are used; the Semaphore just keeps a count of the  number available and acts accordingly. Semaphores are often used to restrict the number of threads than can access some (physical or logical)  resource.

上面是官方给予该类的介绍,信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。

举个例子,公共厕所只有3个位子,有10个人要上厕所.一开始3个位都是空的,那么将有3个人先后占得坑,其它人只要在外面等待.如果有一个人上完厕所,然后等待中的7人中将有一个可以去上厕所.也有可能同时有两人OK,那么也将会同时有两人补位.简单说就是你必须有空位了,才能去上厕所.

上厕所的例子虽不雅观,但令人印象深刻,本来想举ATM机取钱的例子的,但意思一样,还是举上厕所吧.

Semaphore的作用就是控制位置的分配,一般情况下位置的分配是随机的,可以在实例化对象时设置规则进行排序.

2.实例

先看效果:

 

 

再来看代码:

 

package com.amos.concurrent;import java.util.Random;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;/** * @ClassName: SemaPhoreTest * @Description: 线程通信中的"信号灯"* @author: amosli* @email:hi_amos@outlook.com* @date Apr 25, 2014 12:06:22 AM  */public class SemaPhoreTest {    public static void main(String[] args) {        ExecutorService threadPool = Executors.newCachedThreadPool();                final Semaphore semaphore=new Semaphore(3);        for(int i=0;i<10;i++){            threadPool.execute(new Runnable() {                public void run() {                    try {                        semaphore.acquire();//获取一个可用的permits                    } catch (Exception e) {                        e.printStackTrace();                    }                    System.out.println("线程 " + Thread.currentThread().getName()+" 已进入.  " + "目前已经有"+(3-semaphore.availablePermits())+" 个线程进入");                    try {                        Thread.sleep(new Random().nextInt(1000));                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out.println("线程 "+Thread.currentThread().getName()+ " 即将离开...");                    semaphore.release();//释放一个线程                    System.out.println("线程 "+Thread.currentThread().getName()+ " 已离开.  当前有"+(3-semaphore.availablePermits())+"并发");                }            });        }    }}

 

怎么保证是有序的?

上面的代码是不保证顺序的,如果要有个先后顺序,即FIFO,先进先出原则,有个排队,上厕所要排队,只需要将上面的代码改掉一行即可.

final Semaphore semaphore=new Semaphore(3, true);

这样就可以了,其它代码不变.效果如下图所示:

 

3.代码说明

1).如何创建Semaphore?

new Semaphore(3);//无序默认创建是无序的.new Semaphore(3,true);//有序

2)如何获取一个"坑位"?

首先,程序会先检查,"坑"是否已经满了,如果没满,那么可以按需分配,具体代码如下:

          try {semaphore.acquire();//获取一个可用的permits                     } catch (Exception e) {                        e.printStackTrace();                    }

然后,分配完以后,将会把此坑位置为不可用了.

3)如何释放一个"坑位"?

semaphore.release();//释放一个线程

释放完成以后将会把此坑位置为可用的.

 

4.扩展--官方例子

For example, here is a class that uses a semaphore to control access to a pool of items:  class Pool {   private static final int MAX_AVAILABLE = 100;   private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);   public Object getItem() throws InterruptedException {     available.acquire();     return getNextAvailableItem();   }   public void putItem(Object x) {     if (markAsUnused(x))       available.release();   }   // Not a particularly efficient data structure; just for demo   protected Object[] items = ... whatever kinds of items being managed   protected boolean[] used = new boolean[MAX_AVAILABLE];   protected synchronized Object getNextAvailableItem() {     for (int i = 0; i < max_available; ++i) {       if (!used[i]) {          used[i] = true;          return items[i];       }     }     return null; // not reached   }   protected synchronized boolean markasunused(object item) {     for (int i = 0; i < max_available; ++i) {       if (item == items[i]) {          if (used[i]) {            used[i] = false;            return true;          } else            return false;       }     }     return false;   } }

 

 

转载地址:http://hnvbx.baihongyu.com/

你可能感兴趣的文章
数据库三范式是什么?
查看>>
[转载]设置Ubuntu自动连接无线,无须再输入密钥环和无线密码
查看>>
九叔Xen App测试报告
查看>>
Apache配置
查看>>
Ext gridPanel 单元格数据的渲染
查看>>
Android SDK 的下载代理
查看>>
Method Swizzling对Method的要求
查看>>
佛祖保佑,永不宕机
查看>>
四、配置开机自动启动Nginx + PHP【LNMP安装 】
查看>>
LNMP一键安装
查看>>
SQL Server数据库概述
查看>>
Linux 目录结构及内容详解
查看>>
startx命令--Linux命令应用大词典729个命令解读
查看>>
华为3026c交换机配置tftp备份命令
查看>>
Oracle命令导入dmp文件
查看>>
OCP读书笔记(24) - 题库(ExamD)
查看>>
Http、TCP/IP协议与Socket之间的区别(转载)
查看>>
解决Unable to load R3 module ...VBoxDD.dll (VBoxDD):GetLastError=1790
查看>>
.net excel利用NPOI导入oracle
查看>>
vrpie在Visio Studio 中无法调试的问题
查看>>