Semaphore:动态增减信号量,用于控制对某资源访问的同一时间的并发量。类似于令牌,谁拿到令牌(acquire)就可以去执行了,如果没有令牌则需要等待。
【如何获取】:
semaphore.tryAcquire(),尝试获取,不阻塞。
semaphore.acquire(),没信号量可用时,将进行阻塞等,可以被中断。
acquireUninterruptibly():获取信号量,将进行阻塞,但会忽略线程的中断而且不会抛出任何异常。
【如何释放】:
semaphore.release();
线程抛出各种异常,都别忘了在finally中释放信号量;
如果释放的比获取的信号量还多,例如获取了2个,释放了5次,那么当前信号量就动态的增加为5了,要注意。如下图所示:
例子:用信号量semaphore实现生产者与消费者
请仔细体会里面关于仓库的处理,
1 是如何保证入库时,如果仓库满就等待,
2 出库时,如果仓库无货就等待的。
3 以及对仓库只有10个库位的处理。
4 对同步问题的处理。
public class TestSemaphore { public static void main(String[] args) { for (int i = 0; i <= 3; i++) { new Thread(new Producer()).start(); new Thread(new Consumer()).start(); } } //仓库 static WareHouse buffer = new WareHouse(); //生产者 static class Producer implements Runnable{ static int num = 1; public void run() { int n = num++; while(true){ try{ buffer.put(n); System.out.println(">"+n); Thread.sleep(10); }catch (InterruptedException e) { e.printStackTrace(); } } } } static class Consumer implements Runnable{ public void run() { while (true) { try { System.out.println("<"+buffer.take()); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } static class WareHouse{ //非满锁 final Semaphore notFull = new Semaphore(10); //非空锁 final Semaphore notEmpty = new Semaphore(0); //互斥锁 final Semaphore mutex = new Semaphore(1); //库存容量 final Object[] items = new Object[10]; int putPosi, takePosi, count; public void put(Object x)throws InterruptedException{ try{ notFull.acquire(); mutex.acquire(); items[putPosi] = x; if (++putPosi == items.length) { putPosi = 0; } count++; }finally{ notEmpty.release(); mutex.release(); } } public Object take()throws InterruptedException{ notEmpty.acquire(); mutex.acquire(); try{ Object x = items[takePosi]; if(++takePosi == items.length){ takePosi = 0; } --count; return x; }finally{ notFull.release(); mutex.release(); } } } }
也可以把Semaphore当锁来使用
当信号量的数量上限是1时,Semaphore可以被当做锁来使用。通过take和release方法来保护关键区域。请看下面的例子:
BoundedSemaphore semaphore = new BoundedSemaphore(1); ... semaphore.acquire(); try{ //critical section } finally { semaphore.release(); }