1.Semaphore作用
synchronized只能让一段代码同步执行,而Semaphore可以控制并发数量
2.Semaphore常用API(构造方法就不说了,就2个挺简单,查下API文档)
method | description |
---|---|
void acquire() | Acquires a permit from this semaphore, blocking until one is available, or the thread is interrupted |
void acquire(int permits) | Acquires the given number of permits from this semaphore, blocking until all are available, or the thread is interrupted. |
void acquireUninterruptibly() | Acquires a permit from this semaphore, blocking until one is available. |
void acquireUninterruptibly(int permits) | Acquires the given number of permits from this semaphore, blocking until all are available. |
int availablePermits() | Returns the current number of permits available in this semaphore. |
int drainPermits() | Acquires and returns all permits that are immediately available. |
int getQueueLength() | Returns an estimate of the number of threads waiting to acquire. |
boolean hasQueuedThreads() | Queries whether any threads are waiting to acquire. |
boolean isFair() | Returns true if this semaphore has fairness set true. |
void release() | Releases a permit, returning it to the semaphore. |
void release(int permits) | Releases the given number of permits, returning them to the semaphore. |
boolean tryAcquire() | Acquires a permit from this semaphore, only if one is available at the time of invocation. |
boolean tryAcquire(int permits) | Acquires the given number of permits from this semaphore, only if all are available at the time of invocation. |
boolean tryAcquire(int permits, long timeout, TimeUnit unit) | Acquires the given number of permits from this semaphore, if all become available within the given waiting time and the current thread has not been interrupted. |
boolean tryAcquire(long timeout, TimeUnit unit) | Acquires a permit from this semaphore, if one becomes available within the given waiting time and the current thread has not been interrupted. |
3.详解API用法
-
acquire
# acquire(int permits)和acquire()类似,这里就只演示acquire() public class TempDemo { private static Semaphore semaphore = new Semaphore(1); public static void test() { try { semaphore.acquire(); System.out.println(Thread.currentThread().getName() + " 开始执行..."); // 这里就是让线程在执行中 for (int index = 0; index < Integer.MAX_VALUE / 120; index ++) { String ss = new String(); Math.random(); } System.out.println(Thread.currentThread().getName() + " 执行结束..."); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); } } public static void main(String[] args) throws Exception { Thread[] threads = new Thread[5]; for (int index = 0; index < threads.length; index ++) { threads[index] = new Thread(() -> { test(); }); threads[index].setName("Thread-" + index); threads[index].start(); } for (int index = 0; index < threads.length; index ++) { threads[index].join(); } } } 注意:acquire()是可以被中断的,例如把线程0中断,线程0就中断执行了: Thread[] threads = new Thread[5]; for (int index = 0; index < threads.length; index ++) { threads[index] = new Thread(() -> { test(); }); threads[index].setName("Thread-" + index); threads[index].start(); } threads[0].interrupt(); // 中断线程0 for (int index = 0; index < threads.length; index ++) { threads[index].join(); }
-
acquireUninterruptibly
# acquireUninterruptibly和acquire的区别在于,acquireUninterruptibly不可以中断,如下代码虽然有显示的中断, 但是线程0没有受到影响 public class TempDemo { private static Semaphore semaphore = new Semaphore(1); public static void test() { semaphore.acquireUninterruptibly(); System.out.println(Thread.currentThread().getName() + " 开始执行..."); // 这里就是让线程在执行中 for (int index = 0; index < Integer.MAX_VALUE / 120; index ++) { String ss = new String(); Math.random(); } System.out.println(Thread.currentThread().getName() + " 执行结束..."); semaphore.release(); } public static void main(String[] args) throws Exception { Thread[] threads = new Thread[5]; for (int index = 0; index < threads.length; index ++) { threads[index] = new Thread(() -> { test(); }); threads[index].setName("Thread-" + index); threads[index].start(); } threads[0].interrupt(); for (int index = 0; index < threads.length; index ++) { threads[index].join(); } } }
-
tryAcquire
# tryAcquire(int permits)和tryAcquire类似就不说了 public class TempDemo { private static Semaphore semaphore = new Semaphore(1); public static void test() { if (semaphore.tryAcquire()) { System.out.println(Thread.currentThread().getName() + " 开始执行..."); // 这里就是让线程在执行中 for (int index = 0; index < Integer.MAX_VALUE / 120; index ++) { String ss = new String(); Math.random(); } System.out.println(Thread.currentThread().getName() + " 执行结束..."); semaphore.release(); } else { System.out.println(Thread.currentThread().getName() + " 没有获取到凭证"); } } public static void main(String[] args) throws Exception { Thread[] threads = new Thread[5]; for (int index = 0; index < threads.length; index ++) { threads[index] = new Thread(() -> { test(); }); threads[index].setName("Thread-" + index); threads[index].start(); } for (int index = 0; index < threads.length; index ++) { threads[index].join(); } } } # tryAcquire(long timeout, TimeUnit unit) 在规定的时间内获取到凭证就返回,也是可以被中断的
-
release
# release释放资源,调用几次就释放几个,这个一定要注意,下面这段代码输出的是3 public class TempDemo { private static Semaphore semaphore = new Semaphore(1); public static void main(String[] args) throws Exception { semaphore.release(); semaphore.release(); System.out.println("permits: " + semaphore.availablePermits()); } }
-
other
isFair()就不说了,相对公平而已,个人觉得用处不是很大吧,可能自己了解不够深入 getQueueLength()估算等待线程数 hasQueuedThreads()是否有等待线程 drainPermits()清空permits,并返回permits
4.多路进-多处理-多出路
# 也就是多个线程访问一段代码,这段代码多个线程可以同时执行
public class TempDemo {
private static Semaphore semaphore = new Semaphore(2);
public static void test() {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " 开始执行...");
// 这里就是让线程在执行中
for (int index = 0; index < Integer.MAX_VALUE / 120; index ++) {
String ss = new String();
Math.random();
}
System.out.println(Thread.currentThread().getName() + " 执行结束...");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
public static void main(String[] args) throws Exception {
Thread[] threads = new Thread[5];
for (int index = 0; index < threads.length; index ++) {
threads[index] = new Thread(() -> {
test();
});
threads[index].setName("Thread-" + index);
threads[index].start();
}
for (int index = 0; index < threads.length; index ++) {
threads[index].join();
}
}
}
5.多路进-单处理-多出路
# 看代码吧 挺简单的
public class TempDemo {
private static Semaphore semaphore = new Semaphore(2);
private static ReentrantLock lock = new ReentrantLock();
public static void test() {
try {
semaphore.acquire();
lock.lock();
System.out.println(Thread.currentThread().getName() + " 开始执行...");
// 这里就是让线程在执行中
for (int index = 0; index < Integer.MAX_VALUE / 120; index ++) {
String ss = new String();
Math.random();
}
System.out.println(Thread.currentThread().getName() + " 执行结束...");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
semaphore.release();
}
}
public static void main(String[] args) throws Exception {
Thread[] threads = new Thread[5];
for (int index = 0; index < threads.length; index ++) {
threads[index] = new Thread(() -> {
test();
});
threads[index].setName("Thread-" + index);
threads[index].start();
}
for (int index = 0; index < threads.length; index ++) {
threads[index].join();
}
}
}
6.生产者消费者实现
场景大概是这样的,10个消费者(饭店只能同时5个人吃饭),4厨师,3个服务员,来模拟饭店做菜上菜的生产者消费者模式
public class TempDemo {
public static void main(String[] args) throws Exception {
HotelDemo hotelDemo = new HotelDemo(4, 5, 3);
int threadCount = 10;
Thread[] producerThreads = new Thread[threadCount];
Thread[] consumerThreads = new Thread[threadCount];
for (int index = 0; index < threadCount; index ++) {
// 生产
producerThreads[index] = new Thread(() -> {
hotelDemo.set();
});
producerThreads[index].setName("producer-thread-" + index);
// 消费
consumerThreads[index] = new Thread(() -> {
hotelDemo.get();
});
consumerThreads[index].setName("consumer-thread-" + index);
}
for (int index = 0; index < threadCount; index ++) {
producerThreads[index].start();
consumerThreads[index].start();
}
for (int index = 0; index < threadCount; index ++) {
producerThreads[index].join();
consumerThreads[index].join();
}
}
}
class HotelDemo {
/**
* 厨师数量
*/
private volatile Semaphore producers = null;
/**
* 厨师菜做好通知
*/
private volatile ReentrantLock lock = null;
private volatile Condition sendCondition = null;
/**
* 服务员 做好的菜都要放到服务员手里 如果没有多余的服务员厨师就暂时不做菜
*/
private volatile String[] services = null;
/**
* 消费者数量
*/
private volatile Semaphore consumers = null;
/**
* 消费者消耗了菜
*/
private volatile Condition obtainCondition = null;
public HotelDemo(int producerCount, int consumerCount, int serviceCount) {
producers = new Semaphore(producerCount);
lock = new ReentrantLock();
sendCondition = lock.newCondition();
services = new String[serviceCount];
consumers = new Semaphore(consumerCount);
obtainCondition = lock.newCondition();
}
/**
* 厨师做菜
*/
public void set() {
try {
producers.acquire();
lock.lock();
while (this.isFull()) {
System.out.println(Thread.currentThread().getName() + " 要做饭 但是服务员不够 ");
sendCondition.await();
}
// 厨师做饭要1秒
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName() + " 做饭了 ");
this.add("做饭了");
obtainCondition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
producers.release();
}
}
/**
* 消费者消耗菜
*/
public void get() {
try {
consumers.acquire();
lock.lock();
while (this.isEmpty()) {
System.out.println(Thread.currentThread().getName() + " 要吃饭 饭还没有好 ");
obtainCondition.await();
}
// 假设用户吃饭要2秒
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName() + " 吃饭了");
this.poll();
sendCondition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
consumers.release();
}
}
private synchronized void add(String name) {
for (int index = 0; index < services.length; index ++) {
if (services[index] == null) {
services[index] = name;
return;
}
}
}
private synchronized boolean isFull() {
System.out.println(Arrays.asList(services).toString());
for (int index = 0; index < services.length; index ++) {
if (services[index] == null) {
return false;
}
}
return true;
}
private synchronized String poll() {
for (int index = 0; index < services.length; index ++) {
if (services[index] != null) {
String temp = services[index];
services[index] = null;
return temp;
}
}
return null;
}
private synchronized boolean isEmpty() {
System.out.println(Arrays.asList(services).toString());
for (int index = 0; index < services.length; index ++) {
if (services[index] != null) {
return false;
}
}
return true;
}
}