一个计数信号量。从概念上讲,信号量维护了一个许可集。Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。通常,应该将用于控制资源访问的信号量初始化为公平的,以确保所有线程都可访问资源。为其他的种类的同步控制使用信号量时,非公平排序的吞吐量优势通常要比公平考虑更为重要。此类还提供便捷的方法来同时 acquire
和释放
多个许可。小心,在未将公平设置为 true 时使用这些方法会增加不确定延期的风险。
实例:个人感觉信号量类似限流的阀门,控制流量。下面的实例就是控制线程进入的数目
public class SemaphoreTest {
public void printName(Semaphore sh){
try {
sh.acquire();
System.out.println("当前运行的线程为:"+Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(1);
sh.release();
} catch ( Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
final Semaphore semaphore=new Semaphore(5,true);
// final Semaphore semaphore=new Semaphore(5); //非公平的
final SemaphoreTest sht=new SemaphoreTest();
//每次只能进入5个线程,每次等一秒,这里有100个线程,大致是20S的时间
Long startTime=System.currentTimeMillis();
for (int i=0;i<100;i++){
new Thread(new Runnable() {
@Override
public void run() {
sht.printName(semaphore);
}
}).start();
}
//自旋等待所有线程执行完毕
// 当前线程组中,主线程存活,另外一个我猜测应该是维护semaphore的线程。
while (Thread.activeCount()>2){
}
Long endTime=System.currentTimeMillis();
System.out.println("总计:"+(endTime - startTime));
}
}
上面就是信号量的简单使用方法,下面是API里常用方法,原理和源码后面有时间会补上。
源码剖析
结构:
构造方法:
释放方法流程剖析:
当操作成功时,信号量会放任此线程通过;当修改操作失败,应该是根据信号量允许进入的值有关,跟State有联系。compareAndSetState()操作涉及到了Unsafe类,这个类的方法全是调用C库的东西。除非有openJDK,不然看不到具体实现。我看不到源码,也不知道这个CAS操作是怎么处理的,走了几次断点,如下:
这个是current=3,next=4,CAS操作失败,没有返回true。
这个是current=4,next=5,可以看到CAS操作成功了,断点已经走到return那里。
CAS操作是调用AQS里的方法:
这个是Unsafe类里面的方法:
网上给出的CAS的一些解释: