转自:
http://www.java265.com/JavaCourse/202204/3184.html
下文笔者讲述java中Semaphore类的详解说明,如下所示:
Semaphore(中文翻译:信号量) 我们常用于控制访问某一资源的线程个数, 使用这种方式可使大家按照一定的规则访问某一资源 Semaphore的原理: 通过使用计数器来控制对某一资源的访问 当计数器大于0,则允许访问 当计数器为0时,则拒绝访问 计数器中的计数作为允许访问共享资源的许可 即:访问资源,需从信号量中授予线程许可
方法名 | 备注 |
void acquire() | 从信号量获取一个许可,在无可用许可前,将一直阻塞等待 |
void acquire(int permits) | 获取指定数目的许可,在无可用许可前,也将会一直阻塞等待 |
boolean tryAcquire() | 从信号量尝试获取一个许可,当无可用许可,直接返回false,不会阻塞 |
boolean tryAcquire(int permits) | 尝试获取指定数目的许可,当无可用许可直接返回false |
boolean tryAcquire(int permits, long timeout, TimeUnit unit) | 在指定的时间内尝试从信号量中获取许可,当在指定的时间内获取成功,返回true,否则返回false |
void release() | 释放一个许可,别忘了在finally中使用 注意:多次调用该方法,会使信号量的许可数增加,达到动态扩展的效果 如:初始permits为1,调用了两次release,最大许可会改变为2 |
int availablePermits() | 获取当前信号量可用的许可 |
public Semaphore(int permits) { sync = new NonfairSync(permits); } public Semaphore(int permits, boolean fair) { sync = fair ? new FairSync(permits) : new NonfairSync(permits); } 参数说明: permits:初始许可数,即最大访问线程数 fair:当设置为false时,创建的信号量为非公平锁;当设置为true时,信号量是公平锁
package com.java265.other; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; public class Test16 { public static void main(String[] args) { // 允许最大的获取用户的线程数 int slots = 8; ExecutorService executorService = Executors.newFixedThreadPool(slots); UserUsingSemaphore loginQueue = new UserUsingSemaphore(slots); // 线程池模拟登录 for (int i = 1; i <= slots; i++) { final int num = i; executorService.execute(() -> { if (loginQueue.tryAcquire()) { System.out.println("用户:" + num + "获取成功!"); } else { System.out.println("用户:" + num + "获取失败!"); } }); } executorService.shutdown(); System.out.println("当前可用许可证数:" + loginQueue.availableSlots()); // 此时已经有8个线程,再次获取的时候会返回false if (loginQueue.tryAcquire()) { System.out.println("获取成功!"); } else { System.out.println("资源已经被占满,获取失败!"); } // 有用户释放资源,只释放一个资源 loginQueue.releaseAcquire(); // 再次获取 if (loginQueue.tryAcquire()) { System.out.println("获取成功-2!"); } else { System.out.println("资源已经被占满,获取失败-2!"); } // 再次获取-会失败,因为又没有空余 if (loginQueue.tryAcquire()) { System.out.println("获取成功-3!"); } else { System.out.println("资源已经被占满,获取失败-3!"); } } } /* * 定义一个登录队列,用于获取信号量 */ class UserUsingSemaphore { private Semaphore semaphore; /** * @param 设置信号量的大小 */ public UserUsingSemaphore(int slotLimit) { semaphore = new Semaphore(slotLimit); } boolean tryAcquire() { // 获取一个凭证 return semaphore.tryAcquire(); } /* * 释放凭证 */ void releaseAcquire() { semaphore.release(); } /* * 获取可用的凭证数量 */ int availableSlots() { return semaphore.availablePermits(); } } ------运行以上代码,将输出以下信息------ 用户:1获取成功! 用户:5获取成功! 用户:2获取成功! 用户:4获取成功! 用户:3获取成功! 用户:7获取成功! 用户:6获取成功! 当前可用许可证数:1 资源已经被占满,获取失败! 获取成功-2! 资源已经被占满,获取失败-3! 用户:8获取成功!