Semaphore作用:
以一个停车场运作为例来说明信号量的作用。假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了三辆车,看门人允许其中它们进入进入,然后放下车拦。以后来的车必须在入口等待,直到停车场中有车辆离开。这时,如果有一辆车离开停车场,看门人得知后,打开车拦,放入一辆,如果又离开一辆,则又可以放入一辆,如此往复。
感觉它的运用方式和线程池有点类似,线程池中一共就那么多个线程,先来的任务先运行,后来的任务如果没有获取到线程资源的话,需要先到阻塞队列中等待,线程空闲了之后再从队列中获取它们运行。
(想到可以用它来控制并发量,给每个任务一个权重,然后获取权重的值,哈哈哈)
写个demo测试下:
public class SemaphoreTest { static Semaphore semaphore = new Semaphore(1); static ThreadPoolExecutor pool = new ThreadPoolExecutor(2,2,0L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10)); public static void main(String[] args) { for (int i =0;i<10;i++){ TestThread temp = new TestThread(String.valueOf(i)); pool.submit(temp); } pool.shutdown(); } private static class TestThread implements Runnable{ private String name ; public TestThread(String name) { this.name = name; } @Override public void run() { try { semaphore.acquire(1); System.out.println("Thread " + name + " start Run..."); TimeUnit.SECONDS.sleep(1); System.out.println("Thread " + name + " finish..."); semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); } } } }输出为:
Thread 0 start Run...
Thread 0 finish...
Thread 2 start Run...
Thread 2 finish...
Thread 3 start Run...
Thread 3 finish...
Thread 4 start Run...
Thread 4 finish...
Thread 1 start Run...
Thread 1 finish...
Thread 5 start Run...
Thread 5 finish...
Thread 6 start Run...
Thread 6 finish...
Thread 8 start Run...
Thread 8 finish...
Thread 9 start Run...
Thread 9 finish...
Thread 7 start Run...
Thread 7 finish...
接下来分析下它的源码:
首先是构造函数:
反正公平和非公平只是最新进来的那个线程是先排队还是先获取锁这一点区别,直接看下非公平的构造函数好了。
Permits称为许可。
获取许可acquire():
底层调用的是AQS中的获取共享锁的方法:
获取锁的tryAcquireShared()方法在Semaphore中被重写过的:
感觉这里和ReentrantLock的很像,没有获取到锁的线程会进入AQS的队列排队等待。如果一直没有获取到许可的话,线程会一直等待在这里。
这个if判断有点意思,如果remaingin<0,会直接返回这个负数。然后就会执行到上面的那个d0AcquireSharedInterruptibly()那个方法中,将任务加入队列。
如果remiaing>0,会使用AQS更新state的值,表示获取到许可了。
释放许可release():
默认情况下是将state的值加1,当然也可以加大于1的数。
底层还是使用CAS的方式修改state的值:
然后会通知AQS队列中的head节点,让该线程去获取Permits。
参考:
http://www.cnblogs.com/nullzx/p/5270233.html(Semaphore解释的比较清楚)