Java 多线程 系列文章目录:
- Java 多线程(一)线程间的互斥和同步通信
- Java 多线程(二)同步线程分组问题
- Java 多线程(三)线程池入门 Callable 和 Future
- Java 多线程(四)ThreadPoolExecutor 线程池各参数的意义
- Java 多线程(五)Lock 和 Condition 实现线程同步通信
- Java 多线程(六)Semaphore 实现信号灯
- Java 多线程(七)CyclicBarrier 同步的工具类
- Java 多线程(八)CountDownLatch 同步工具类
- Java 多线程(九)Exchanger 同步工具类
- Java 多线程(十)ArrayBlockingQueue 阻塞队列
- Java 多线程(十一)JDK 同步集合
Semaphore 可以维护当前访问自身的线程个数,并提供了同步机制,使用 Semaphore 可以控制同时访问资源的线程数,例如:实现一个文件允许的并发访问数。
Semaphore 常用的 API 方法:
- Semaphore(int permits, boolean fair)
- acquire()
- availablePermits()
- release()
举个形象的例子:比如厕所一共有 5 个茅坑(new Semaphore(5)),假如有 10 个人(10个线程)要上厕所,那么同时只能有 5 个人能够占用,当占用的 5 个人任何一个让开后(release()方法),其中等待的另外5个人中有一个可以去占用(acquire()方法)这个坑位了。另外等待的 5 个人可以是随机获取优先机会,也可以是按照先来后到的顺序获取机会,这取决于构造方法传入的参数选项:public Semaphore(int permits, boolean fair)
下面我们通过 Semaphore 来实现下上面的场景:
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final Semaphore sp = new Semaphore(3, true);
for (int i = 0; i < 10; i++) {
Runnable runnable = new Runnable() {
public void run() {
try {
sp.acquire();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName()
+ "进入,当前已有" + (3 - sp.availablePermits()) + "个并发");
try {
Thread.sleep((long) (Math.random() * 3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName()
+ "即将离开");
sp.release();
// 下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元
System.out.println("线程" + Thread.currentThread().getName()
+ "已离开,当前已有" + (3 - sp.availablePermits()) + "个并发");
}
};
service.execute(runnable);
}
}
程序执行结果如下:
线程pool-1-thread-1进入,当前已有3个并发
线程pool-1-thread-2进入,当前已有3个并发
线程pool-1-thread-3进入,当前已有3个并发
线程pool-1-thread-1即将离开
线程pool-1-thread-4进入,当前已有3个并发
线程pool-1-thread-1已离开,当前已有3个并发
线程pool-1-thread-3即将离开
线程pool-1-thread-3已离开,当前已有2个并发
线程pool-1-thread-5进入,当前已有3个并发
线程pool-1-thread-5即将离开
线程pool-1-thread-6进入,当前已有3个并发
线程pool-1-thread-5已离开,当前已有3个并发
线程pool-1-thread-2即将离开
线程pool-1-thread-7进入,当前已有3个并发
线程pool-1-thread-2已离开,当前已有3个并发
线程pool-1-thread-6即将离开
线程pool-1-thread-8进入,当前已有3个并发
线程pool-1-thread-6已离开,当前已有3个并发
线程pool-1-thread-4即将离开
线程pool-1-thread-9进入,当前已有3个并发
线程pool-1-thread-4已离开,当前已有3个并发
线程pool-1-thread-8即将离开
线程pool-1-thread-8已离开,当前已有2个并发
线程pool-1-thread-10进入,当前已有3个并发
线程pool-1-thread-7即将离开
线程pool-1-thread-7已离开,当前已有2个并发
线程pool-1-thread-9即将离开
线程pool-1-thread-9已离开,当前已有1个并发
线程pool-1-thread-10即将离开
线程pool-1-thread-10已离开,当前已有0个并发
单个信号量的 Semaphore 对象可以实现互斥锁的功能,并且可以是由一个线程获得锁,再由另外一个线程释放锁,也就是一个线程可以去释放锁,尽管他没有得到 permit,这可以应用到死锁恢复的一些场合。