写在前面:各位看到此博客的小伙伴,如有不对的地方请及时通过私信我或者评论此博客的方式指出,以免误人子弟。多谢!
概念:
Semaphore也是一个线程同步的辅助类,可以维护当前访问自身的线程个数,并提供了同步机制。从概念上讲,Semaphore是一个计数信号量,Semaphore包含一组许可证。
如果有需要的话,每个acquire()方法都会阻塞,直到获取一个可用的许可证。每个release()方法都会释放持有许可证的线程,并且归还Semaphore一个可用的许可证。
使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。
Semaphore 是 synchronized 的加强版,作用是控制同时访问资源的线程个数(控制线程的并发数量)
当Semaphore初始值为1时其实就相当于 synchronized。
常用方法:
1.Semaphore(permits)
初始化许可证数量的构造函数。
2.Semaphore(permits,fair)
初始化许可证数量和是否公平模式的构造函数。
3.availablePermits()
获取当前可用的许可证数量。
4.acquire()
当前线程尝试去获取1个许可证。直到发生以下任意一件事:
1):当前线程获取了1个可用的许可证,则会停止等待,继续执行。
2):当前线程被中断,则会抛出InterruptedException异常,并停止等待,继续执行。
5.acquire(permits)
当前线程尝试去获取permits个许可证。直到发生以下任意一件事:
1):当前线程获取了permits个可用的许可证,则会停止等待,继续执行。
2):当前线程被中断,则会抛出InterruptedException异常,并停止等待,继续执行。
6.tryAcquire()
当前线程尝试去获取1个许可证。
1):如果当前线程获取了1个可用的许可证,则会停止等待,继续执行,并返回true。
2):如果当前线程没有获得这个许可证,也会停止等待,继续执行,并返回false。
7.tryAcquire(permits)
当前线程尝试去获取permits个许可证。
1):如果当前线程获取了permits个可用的许可证,则会停止等待,继续执行,并返回true。
2):如果当前线程没有获得permits个许可证,也会停止等待,继续执行,并返回false。
8.tryAcquire(timeout,TimeUnit)
当前线程在限定时间内,尝试去获取1个许可证。直到发生以下任意一件事:
1):当前线程获取了可用的许可证,则会停止等待,继续执行,并返回true。
2):当前线程等待时间timeout超时,则会停止等待,继续执行,并返回false。
3):当前线程在timeout时间内被中断,则会抛出InterruptedException一次,并停止等待,继续执行。
9.tryAcquire(permits,timeout,TimeUnit)
当前线程在限定时间内,尝试去获取permits个许可证。直到发生以下任意一件事:
1):当前线程获取了可用的permits个许可证,则会停止等待,继续执行,并返回true。
2):当前线程等待时间timeout超时,则会停止等待,继续执行,并返回false。
3):当前线程在timeout时间内被中断,则会抛出InterruptedException一次,并停止等待,继续执行。
10.release()
当前线程释放1个可用的许可证。
11.release(permits)
当前线程释放permits个可用的许可证。
因为平时用的不多,就简单举例记录一下,这个例子包含3个类,一个是线程类,一个是 线程要操作的资源类,一个类是主main方法类:
代码如下:
public class SemaphoreTest {
public static void main(String[] args) {
DoSomething doSomething = new DoSomething();
for (int i=0;i<10;i++){
Task t = new Task(doSomething);
t.start();
}
}
static class DoSomething{
Semaphore semaphore = new Semaphore(2);
public void doSome(){
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + ":开始任务");
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + ":完成任务");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class Task extends Thread{
private DoSomething doSomething;
public Task(DoSomething doSomething){
this.doSomething = doSomething;
}
@Override
public void run() {
doSomething.doSome();
}
}
}
执行结果如下:
可以看出:每次只能有两个线程并行执行,正如前面所说,它的作用就是控制同时访问资源的线程个数,一次只允许permits个线程访问。