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;
} }

Java核心知识点学习----线程中的Semaphore学习,公共厕所排队策略的更多相关文章

  1. java核心知识点----创建线程的第三种方式 Callable 和 Future CompletionService

    前面已经指出通过实现Runnable时,Thread类的作用就是将run()方法包装成线程执行体,那么是否可以直接把任意方法都包装成线程执行体呢?Java目前不行,但其模仿者C#中是可以的. Call ...

  2. Java核心知识点学习----线程中如何创建锁和使用锁 Lock,设计一个缓存系统

    理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...

  3. Java核心知识点学习----多线程中的阻塞队列,ArrayBlockingQueue介绍

    1.什么是阻塞队列? 所谓队列,遵循的是先进先出原则(FIFO),阻塞队列,即是数据共享时,A在写数据时,B想读同一数据,那么就将发生阻塞了. 看一下线程的四种状态,首先是新创建一个线程,然后,通过s ...

  4. Java核心知识点学习----使用Condition控制线程通信

    一.需求 实现线程间的通信,主线程循环3次后,子线程2循环2次,子线程3循环3次,然后主线程接着循环3次,如此循环3次. 即:A->B->C---A->B->C---A-> ...

  5. Java核心知识点 --- 线程中如何创建锁和使用锁 Lock , 设计一个缓存系统

    理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...

  6. Java面试知识点之线程篇(三)

    前言:这里继续对java线程相关知识点进行总结,不能间断. 1.yield()方法 yield()的作用是让步.它能让当前线程由“运行状态”进入到“就绪状态”,从而让其它具有相同优先级的等待线程获取执 ...

  7. Java面试知识点之线程篇(二)

    前言:接上篇,这里继续对java线程相关知识点进行总结. 1.notify和notifyall的区别 notify()方法能够唤醒一个正在等待该对象的monitor的线程,当有多个线程都在等待该对象的 ...

  8. Java面试知识点之线程篇(一)

    前言:在Java面试中,一定会遇到线程相关问题,因此笔者在这里总结Java中有关线程方面知识点,多数从网上得来(文中会贴出主要参考链接),有些也是笔者在面试中所遇到的问题,如有错误,请不吝指正.主要参 ...

  9. Java:类集框架中集合的学习

    Java:类集框架中集合的学习 集合 Java:Set的学习 Set是类集框架中的集合类.集合是不按特定的方式排序,并且没有重复对象的一种类. Q:Set如何操作?Set中的不按特定方式排序是怎么排序 ...

随机推荐

  1. SQL2005 : 如何在SQL Server Profiler (事件查看器)中 跟踪查看死锁恢复

    SQL Profiler 通过 SQL Profiler 工具程序,可监控应用程序如何访问数据库引擎.普通来说,当系统性能需要优化或是应用程序对数据库访问的结果不合预期,都可以使用该工具确认视图问题所 ...

  2. C++常见gcc编译链接错误解决方法

    除非明确说明,本文内容仅针对x86/x86_64的Linux开发环境,有朋友说baidu不到,开个贴记录一下(加粗字体是关键词): 用“-Wl,-Bstatic”指定链接静态库,使用“-Wl,-Bdy ...

  3. 黄聪:说说JSON和JSONP,也许你会豁然开朗(转)

    前言 由于Sencha Touch 2这种开发模式的特性,基本决定了它原生的数据交互行为几乎只能通过AJAX来实现. 当然了,通过调用强大的PhoneGap插件然后打包,你可以实现100%的Socke ...

  4. IIS部署WCF

    IIS部署WCF [转载自——http://www.cnblogs.com/starksoft/p/4992059.html] 1 部署IIS 1.1 安装WAS IIS原本是不支持非HTTP协议的服 ...

  5. DataSet读取XML

    string file = File.ReadAllText("c://123.xml", Encoding.Default); using (DataSet ds = new D ...

  6. 纸上谈兵:哈希表(hash table)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! HASH 哈希表(hash table)是从一个集合A到另一个集合B的映射(map ...

  7. 【python】django-celery 实现django项目定时任务

    官方:https://pypi.python.org/pypi/django-celery/ 参考:http://www.weiguda.com/blog/73/ 参考:http://www.liao ...

  8. MSsql bcp

    --将test_1表导出在F盘根目录下/ reconfigure EXEC master..xp_cmdshell 'bcp test.dbo.test_1 out f:\abc.txt -c -q ...

  9. git 代码组织

    在20145306CSAPP2E文件夹下建立相应的文件夹: src:存放源代码文件 include: 存放头文件 bin:存放编译后的目标文件.可执行文件等 lib:存放项目所需的静态库.动态(共享) ...

  10. 【EF学习笔记08】----------加载关联表的数据 显式加载

    显式加载 讲解之前,先来看一下我们的数据库结构:班级表 学生表 加载从表集合类型 //显示加载 Console.WriteLine("=========查询集合===========&quo ...