Java并发编程 之Semaphore 和 Exchanger
Semaphore(信号量📶)
用于线程同步,控制并发的工具类
- 操作:
- 初始化
- 构造函数指定并发的数目(permits)
- 减少
- acquire()/ acquire(int size) 用于减少可用的并发数,
- tryAcquire() 返回此次此刻是否有可用的资源、/tryAcquire(long timeout, TimeUnit unit) 是前者的衍生,如果在规定的时间内无法获取到到有效的资源才回返回信息
- 增加
- release() /release(int permits) 释放获取的资源,当释放的资源数大于现有资源数,就会增加多余的部分
- 其他
- availablePermits() 返回资源总数
- drainPermits() 有效资源数
- reducePermits(int reduction) 手动增加资源数
结构介绍
- 初始化
内部通过 通过使用 Sync 的旋转锁来保持线程的同步,而NonfairSync(非公平锁:胜者为王,随机争强)与FairSync(非公平锁:先到先得) 的两种锁实现 可指定使用的锁的模式(默认使用非公平锁保持性能高效)
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
Exchager(交换者)
用于线程的之间的 资源交换信息
- 操作
- exchange(V x) 线程阻塞 ,直到信息获取到
- exchange(V x, long timeout, TimeUnit unit) 在规定时间内阻塞
缺点:
- 信息的交换方无法指定
- exchange(T t) 方法,即使接受信息别的线程信息,发送信息 t.对于只想接受信息需求,无法做到
- 只有偶数个的线程才能使 ,每个线程摆脱阻塞状态
- 可用性不是很强,存在很鸡肋
代码
private static final Logger log = LoggerFactory.getLogger(Test1.class);
@Test
public void semaphoreTest() throws InterruptedException {
Semaphore semaphore = new Semaphore(2);
semaphoreTestLog(semaphore);
// 永久阻塞
// semaphore.acquire(2);
// 线程阻塞10S
boolean b = semaphore.tryAcquire(3, TimeUnit.SECONDS);
semaphoreTestLog(semaphore);
log.info(“Semaphore get 10 3 Sec {}”, b);
semaphore.release(3);
semaphoreTestLog(semaphore);
// 比当前的总量大时 会发生扩充多余部分
semaphore.release(4);
semaphoreTestLog(semaphore);
}
/**
* 打印 semaphore 日志
*
* @param semaphore
*/
private void semaphoreTestLog(Semaphore semaphore) {
log.info("Semaphore size {},可用数:{},阻塞长度:{}", semaphore.availablePermits(), semaphore.drainPermits(), semaphore.getQueueLength());
}
public static class MyThread implements Runnable {
private final Exchanger<String> exchanger;
private final String message;
private static final Logger log = LoggerFactory.getLogger(MyThread.class);
public MyThread(Exchanger<String> exchanger, String message) {
super();
this.exchanger = exchanger;
this.message = message;
}
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see Thread#run()
*/
@Override
public void run() {
try {
log.info("线程名称:[{}],获取的信息:{}", Thread.currentThread().getName(), exchanger.exchange(message));
} catch (InterruptedException e) {
log.error(e.getMessage(), e);
}
}
}
@Test
public void exchangerTest() throws InterruptedException {
/**
* 无法指定 发送的消息接收方的 信息交换,其必须双方都进行交换才可获得消息
*/
List<String> messageList = Arrays.asList("A的信息", "B 的信息", "C 的信息", "D 的信息");
Exchanger<String> exchanger = new Exchanger<>();
for (String message : messageList) {
Thread thread = new Thread(new MyThread(exchanger, message));
thread.setName(message);
thread.start();
}
Thread.sleep(1000);
}
```