Semaphore对象我们可以使用的方法如下:
/*
semaphore.acquire()
semaphore.acquire(int permits)
semaphore.tryAcquire()
semaphore.tryAcquire(int permits)
semaphore.tryAcquire(long timeout, TimeUnit unit)
semaphore.release()
semaphore.release(int permits)
semaphore.acquireUninterruptibly()
semaphore.acquireUninterruptibly(int permits)
semaphore.availablePermits()
semaphore.drainPermits()
semaphore.getQueueLength()
semaphore.hasQueuedThreads()
semaphore.isFair()
semaphore.wait()
semaphore.wait(long timeout)
semaphore.wait(long timeout, int nanos)
semaphore.notify()
semaphore.notifyAll()
*/
范例1:
package com.contoso;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SemaphoreExample1 {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
Semaphore semaphore = new Semaphore(3);// 初始化许可证计数器,3个许可证表示允许并发线程的个数等于3
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Runnable t = () -> {
try {
System.out.println(Thread.currentThread().getName() + " before acquire() " + formatter.format(new Date()));
// 如果一旦有1个线程调用acquire()方法,那么许可证计数器就会减1,
// 当计数器从3累减0时,其它线程都会被阻塞,只有获得许可证的这3个线程会同时执行
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " after acquire() " + formatter.format(new Date()));
Thread.sleep(2000); // 模拟工作线程需要的时间
System.out.println(Thread.currentThread().getName() + " work finished " + formatter.format(new Date()));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放全部线程持有的许可证,让许可证计数器重新归位到3个许可证
// 如此往复地执行完全部的线程
semaphore.release();
}
};
for (int i = 0; i < 10; i++) {
executor.execute(t);
}
executor.shutdown();
}
}
run:
pool-1-thread-1 before acquire() 2019-10-23 15:01:57.122
pool-1-thread-1 after acquire() 2019-10-23 15:01:57.124
pool-1-thread-2 before acquire() 2019-10-23 15:01:57.124
pool-1-thread-2 after acquire() 2019-10-23 15:01:57.125
pool-1-thread-6 before acquire() 2019-10-23 15:01:57.126
pool-1-thread-6 after acquire() 2019-10-23 15:01:57.126
pool-1-thread-5 before acquire() 2019-10-23 15:01:57.126
pool-1-thread-4 before acquire() 2019-10-23 15:01:57.126
pool-1-thread-3 before acquire() 2019-10-23 15:01:57.125
pool-1-thread-8 before acquire() 2019-10-23 15:01:57.128
pool-1-thread-7 before acquire() 2019-10-23 15:01:57.128
pool-1-thread-9 before acquire() 2019-10-23 15:01:57.129
pool-1-thread-10 before acquire() 2019-10-23 15:01:57.129
pool-1-thread-1 work finished 2019-10-23 15:01:59.125
pool-1-thread-5 after acquire() 2019-10-23 15:01:59.125
pool-1-thread-2 work finished 2019-10-23 15:01:59.127
pool-1-thread-4 after acquire() 2019-10-23 15:01:59.127
pool-1-thread-6 work finished 2019-10-23 15:01:59.128
pool-1-thread-3 after acquire() 2019-10-23 15:01:59.128
pool-1-thread-5 work finished 2019-10-23 15:02:01.125
pool-1-thread-8 after acquire() 2019-10-23 15:02:01.125
pool-1-thread-4 work finished 2019-10-23 15:02:01.127
pool-1-thread-7 after acquire() 2019-10-23 15:02:01.127
pool-1-thread-3 work finished 2019-10-23 15:02:01.128
pool-1-thread-9 after acquire() 2019-10-23 15:02:01.128
pool-1-thread-8 work finished 2019-10-23 15:02:03.126
pool-1-thread-10 after acquire() 2019-10-23 15:02:03.126
pool-1-thread-7 work finished 2019-10-23 15:02:03.128
pool-1-thread-9 work finished 2019-10-23 15:02:03.129
pool-1-thread-10 work finished 2019-10-23 15:02:05.126
BUILD SUCCESSFUL (total time: 8 seconds)
范例1中控制台打印的输出内容可读性太差,重新分组一下,输出信息可读性会更好
run:
pool-1-thread-1 before acquire() 2019-10-23 15:01:57.122
pool-1-thread-1 after acquire() 2019-10-23 15:01:57.124
pool-1-thread-2 before acquire() 2019-10-23 15:01:57.124
pool-1-thread-6 before acquire() 2019-10-23 15:01:57.126
pool-1-thread-5 before acquire() 2019-10-23 15:01:57.126
pool-1-thread-4 before acquire() 2019-10-23 15:01:57.126
pool-1-thread-3 before acquire() 2019-10-23 15:01:57.125
pool-1-thread-8 before acquire() 2019-10-23 15:01:57.128
pool-1-thread-7 before acquire() 2019-10-23 15:01:57.128
pool-1-thread-9 before acquire() 2019-10-23 15:01:57.129
pool-1-thread-10 before acquire() 2019-10-23 15:01:57.129
pool-1-thread-2 after acquire() 2019-10-23 15:01:57.125
pool-1-thread-6 after acquire() 2019-10-23 15:01:57.126
pool-1-thread-5 after acquire() 2019-10-23 15:01:59.125
pool-1-thread-4 after acquire() 2019-10-23 15:01:59.127
pool-1-thread-3 after acquire() 2019-10-23 15:01:59.128
pool-1-thread-8 after acquire() 2019-10-23 15:02:01.125
pool-1-thread-7 after acquire() 2019-10-23 15:02:01.127
pool-1-thread-9 after acquire() 2019-10-23 15:02:01.128
pool-1-thread-10 after acquire() 2019-10-23 15:02:03.126
pool-1-thread-1 work finished 2019-10-23 15:01:59.125
pool-1-thread-2 work finished 2019-10-23 15:01:59.127
pool-1-thread-6 work finished 2019-10-23 15:01:59.128
pool-1-thread-5 work finished 2019-10-23 15:02:01.125
pool-1-thread-4 work finished 2019-10-23 15:02:01.127
pool-1-thread-3 work finished 2019-10-23 15:02:01.128
pool-1-thread-8 work finished 2019-10-23 15:02:03.126
pool-1-thread-7 work finished 2019-10-23 15:02:03.128
pool-1-thread-9 work finished 2019-10-23 15:02:03.129
pool-1-thread-10 work finished 2019-10-23 15:02:05.126
BUILD SUCCESSFUL (total time: 8 seconds)
范例中相应的这3行代码如果修改成如下这样
Semaphore semaphore = new Semaphore(3); semaphore.acquire(2);semaphore.release(2);
那么打印输出结果表明 ------ 并发数为1,效率很低
run:
pool-1-thread-1 before acquire() 2019-10-23 17:58:36.799
pool-1-thread-3 before acquire() 2019-10-23 17:58:36.799
pool-1-thread-2 before acquire() 2019-10-23 17:58:36.799
pool-1-thread-5 before acquire() 2019-10-23 17:58:36.800
pool-1-thread-6 before acquire() 2019-10-23 17:58:36.800
pool-1-thread-7 before acquire() 2019-10-23 17:58:36.801
pool-1-thread-10 before acquire() 2019-10-23 17:58:36.801
pool-1-thread-8 before acquire() 2019-10-23 17:58:36.801
pool-1-thread-4 before acquire() 2019-10-23 17:58:36.801
pool-1-thread-9 before acquire() 2019-10-23 17:58:36.801
pool-1-thread-3 after acquire() 2019-10-23 17:58:36.799
pool-1-thread-1 after acquire() 2019-10-23 17:58:38.800
pool-1-thread-2 after acquire() 2019-10-23 17:58:40.800
pool-1-thread-5 after acquire() 2019-10-23 17:58:42.801
pool-1-thread-6 after acquire() 2019-10-23 17:58:44.802
pool-1-thread-7 after acquire() 2019-10-23 17:58:46.802
pool-1-thread-10 after acquire() 2019-10-23 17:58:48.802
pool-1-thread-8 after acquire() 2019-10-23 17:58:50.802
pool-1-thread-4 after acquire() 2019-10-23 17:58:52.803
pool-1-thread-9 after acquire() 2019-10-23 17:58:54.803
pool-1-thread-3 work finished 2019-10-23 17:58:38.800
pool-1-thread-1 work finished 2019-10-23 17:58:40.800
pool-1-thread-2 work finished 2019-10-23 17:58:42.801
pool-1-thread-5 work finished 2019-10-23 17:58:44.802
pool-1-thread-6 work finished 2019-10-23 17:58:46.802
pool-1-thread-7 work finished 2019-10-23 17:58:48.802
pool-1-thread-10 work finished 2019-10-23 17:58:50.802
pool-1-thread-8 work finished 2019-10-23 17:58:52.803
pool-1-thread-4 work finished 2019-10-23 17:58:54.803
pool-1-thread-9 work finished 2019-10-23 17:58:56.804
BUILD SUCCESSFUL (total time: 20 seconds)
范例中相应的这3行代码如果修改成如下这样
Semaphore semaphore = new Semaphore(4); semaphore.acquire(2);semaphore.release(2);
那么打印输出结果表明 ------ 并发数为2
run:
pool-1-thread-3 before acquire() 2019-10-23 17:53:52.329
pool-1-thread-6 before acquire() 2019-10-23 17:53:52.329
pool-1-thread-9 before acquire() 2019-10-23 17:53:52.330
pool-1-thread-1 before acquire() 2019-10-23 17:53:52.329
pool-1-thread-5 before acquire() 2019-10-23 17:53:52.329
pool-1-thread-4 before acquire() 2019-10-23 17:53:52.329
pool-1-thread-2 before acquire() 2019-10-23 17:53:52.329
pool-1-thread-10 before acquire() 2019-10-23 17:53:52.330
pool-1-thread-7 before acquire() 2019-10-23 17:53:52.330
pool-1-thread-8 before acquire() 2019-10-23 17:53:52.330
pool-1-thread-6 after acquire() 2019-10-23 17:53:52.330
pool-1-thread-3 after acquire() 2019-10-23 17:53:52.330
pool-1-thread-9 after acquire() 2019-10-23 17:53:54.331
pool-1-thread-1 after acquire() 2019-10-23 17:53:54.331
pool-1-thread-5 after acquire() 2019-10-23 17:53:56.332
pool-1-thread-4 after acquire() 2019-10-23 17:53:56.332
pool-1-thread-2 after acquire() 2019-10-23 17:53:58.332
pool-1-thread-10 after acquire() 2019-10-23 17:53:58.333
pool-1-thread-7 after acquire() 2019-10-23 17:54:00.332
pool-1-thread-8 after acquire() 2019-10-23 17:54:00.333
pool-1-thread-3 work finished 2019-10-23 17:53:54.331
pool-1-thread-6 work finished 2019-10-23 17:53:54.331
pool-1-thread-1 work finished 2019-10-23 17:53:56.332
pool-1-thread-9 work finished 2019-10-23 17:53:56.332
pool-1-thread-4 work finished 2019-10-23 17:53:58.332
pool-1-thread-5 work finished 2019-10-23 17:53:58.332
pool-1-thread-2 work finished 2019-10-23 17:54:00.332
pool-1-thread-10 work finished 2019-10-23 17:54:00.333
pool-1-thread-7 work finished 2019-10-23 17:54:02.333
pool-1-thread-8 work finished 2019-10-23 17:54:02.333
BUILD SUCCESSFUL (total time: 10 seconds)
范例中相应的这3行代码如果修改成如下这样
Semaphore semaphore = new Semaphore(4); semaphore.acquire(1);semaphore.release(1);
那么打印输出结果表明 ------ 并发数为4,性能最好,相当于semaphore.acquire();semaphore.release();
run:
pool-1-thread-2 before acquire() 2019-10-23 18:06:00.337
pool-1-thread-6 before acquire() 2019-10-23 18:06:00.337
pool-1-thread-5 before acquire() 2019-10-23 18:06:00.337
pool-1-thread-3 before acquire() 2019-10-23 18:06:00.337
pool-1-thread-1 before acquire() 2019-10-23 18:06:00.336
pool-1-thread-4 before acquire() 2019-10-23 18:06:00.337
pool-1-thread-8 before acquire() 2019-10-23 18:06:00.338
pool-1-thread-7 before acquire() 2019-10-23 18:06:00.338
pool-1-thread-9 before acquire() 2019-10-23 18:06:00.338
pool-1-thread-10 before acquire() 2019-10-23 18:06:00.338
pool-1-thread-6 after acquire() 2019-10-23 18:06:00.337
pool-1-thread-5 after acquire() 2019-10-23 18:06:00.337
pool-1-thread-2 after acquire() 2019-10-23 18:06:00.337
pool-1-thread-3 after acquire() 2019-10-23 18:06:00.338
pool-1-thread-1 after acquire() 2019-10-23 18:06:02.338
pool-1-thread-4 after acquire() 2019-10-23 18:06:02.338
pool-1-thread-8 after acquire() 2019-10-23 18:06:02.338
pool-1-thread-7 after acquire() 2019-10-23 18:06:02.339
pool-1-thread-9 after acquire() 2019-10-23 18:06:04.339
pool-1-thread-10 after acquire() 2019-10-23 18:06:04.339
pool-1-thread-5 work finished 2019-10-23 18:06:02.338
pool-1-thread-3 work finished 2019-10-23 18:06:02.338
pool-1-thread-2 work finished 2019-10-23 18:06:02.338
pool-1-thread-6 work finished 2019-10-23 18:06:02.339
pool-1-thread-4 work finished 2019-10-23 18:06:04.339
pool-1-thread-1 work finished 2019-10-23 18:06:04.339
pool-1-thread-7 work finished 2019-10-23 18:06:04.340
pool-1-thread-8 work finished 2019-10-23 18:06:04.340
pool-1-thread-10 work finished 2019-10-23 18:06:06.340
pool-1-thread-9 work finished 2019-10-23 18:06:06.340
BUILD SUCCESSFUL (total time: 6 seconds)
范例2:
package com.contoso;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SemaphoreExample2 {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
Semaphore semaphore = new Semaphore(3);// 初始化许可证计数器,3个许可证表示允许并发线程的个数等于3
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Runnable t = () -> {
try {
System.out.println(Thread.currentThread().getName() + " before acquire() " + formatter.format(new Date()));
// 如果一旦有1个线程调用tryAcquire()方法获取锁,那么许可证计数器就会减1,tryAcquire()方法返回true
// 当计数器从3累减0时,其它线程都会被阻塞,只有获得许可证的这3个线程会同时执行
if (semaphore.tryAcquire()) {
System.out.println(Thread.currentThread().getName() + " after acquire() " + formatter.format(new Date()));
Thread.sleep(500); // 模拟工作线程需要的时间
System.out.println(Thread.currentThread().getName() + " work finished " + formatter.format(new Date()));
semaphore.release(); // 不能写到finally里释放
// 释放全部线程持有的许可证,让许可证计数器重新归位到3个许可证
// 如此往复地执行后续0.5秒后获得许可证的3个线程
} else {
System.out.println(Thread.currentThread().getName() + " tryAcquire() has no permit " + formatter.format(new Date()));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
};
for (int i = 0; i < 20; i++) {
executor.execute(t);
}
executor.shutdown();
}
控制台打印输出的信息是杂乱的,进行重新归类后的信息很方便大家阅读
run:
pool-1-thread-3 before acquire() 2019-10-23 21:44:38.245
pool-1-thread-2 before acquire() 2019-10-23 21:44:38.245
pool-1-thread-6 before acquire() 2019-10-23 21:44:38.245
pool-1-thread-1 before acquire() 2019-10-23 21:44:38.245
pool-1-thread-5 before acquire() 2019-10-23 21:44:38.247
pool-1-thread-7 before acquire() 2019-10-23 21:44:38.247
pool-1-thread-4 before acquire() 2019-10-23 21:44:38.246
pool-1-thread-8 before acquire() 2019-10-23 21:44:38.248
pool-1-thread-9 before acquire() 2019-10-23 21:44:38.248
pool-1-thread-10 before acquire() 2019-10-23 21:44:38.248
pool-1-thread-13 before acquire() 2019-10-23 21:44:38.248
pool-1-thread-14 before acquire() 2019-10-23 21:44:38.249
pool-1-thread-12 before acquire() 2019-10-23 21:44:38.248
pool-1-thread-15 before acquire() 2019-10-23 21:44:38.249
pool-1-thread-16 before acquire() 2019-10-23 21:44:38.249
pool-1-thread-11 before acquire() 2019-10-23 21:44:38.249
pool-1-thread-20 before acquire() 2019-10-23 21:44:38.249
pool-1-thread-19 before acquire() 2019-10-23 21:44:38.249
pool-1-thread-17 before acquire() 2019-10-23 21:44:38.250
pool-1-thread-18 before acquire() 2019-10-23 21:44:38.250
pool-1-thread-2 after acquire() 2019-10-23 21:44:38.246
pool-1-thread-6 after acquire() 2019-10-23 21:44:38.246
pool-1-thread-3 after acquire() 2019-10-23 21:44:38.246
pool-1-thread-1 tryAcquire() has no permit 2019-10-23 21:44:38.246
pool-1-thread-5 tryAcquire() has no permit 2019-10-23 21:44:38.247
pool-1-thread-7 tryAcquire() has no permit 2019-10-23 21:44:38.247
pool-1-thread-4 tryAcquire() has no permit 2019-10-23 21:44:38.248
pool-1-thread-8 tryAcquire() has no permit 2019-10-23 21:44:38.248
pool-1-thread-9 tryAcquire() has no permit 2019-10-23 21:44:38.248
pool-1-thread-12 tryAcquire() has no permit 2019-10-23 21:44:38.249
pool-1-thread-14 tryAcquire() has no permit 2019-10-23 21:44:38.249
pool-1-thread-13 tryAcquire() has no permit 2019-10-23 21:44:38.249
pool-1-thread-10 tryAcquire() has no permit 2019-10-23 21:44:38.249
pool-1-thread-15 tryAcquire() has no permit 2019-10-23 21:44:38.249
pool-1-thread-16 tryAcquire() has no permit 2019-10-23 21:44:38.249
pool-1-thread-20 tryAcquire() has no permit 2019-10-23 21:44:38.250
pool-1-thread-11 tryAcquire() has no permit 2019-10-23 21:44:38.250
pool-1-thread-19 tryAcquire() has no permit 2019-10-23 21:44:38.250
pool-1-thread-17 tryAcquire() has no permit 2019-10-23 21:44:38.250
pool-1-thread-18 tryAcquire() has no permit 2019-10-23 21:44:38.250
pool-1-thread-3 work finished 2019-10-23 21:44:38.747
pool-1-thread-6 work finished 2019-10-23 21:44:38.747
pool-1-thread-2 work finished 2019-10-23 21:44:38.747
BUILD SUCCESSFUL (total time: 0 seconds)