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