规律:
多线程协作中,一般被考虑使用的,无非就是:
(同步工具类) Semaphore( semaphore.acquire();消耗许可数,许可数为负数时,当前线程将被阻塞 semaphore.release();增加许可数 )
CountDownLatch( countDown.countDown() 初始值减1,当前线程总是不会被阻塞 countDown.await()若值不为0则会被阻塞,等待初始值减为0才会恢复 )
CyclicBarrier( cyclicBarrier.await() 初始值减1,并阻塞等待初始值减为0。最后一个线程将它减为0之后,若有指定任务,则还需要负责执行指定任务完毕,之后会唤醒之前被阻塞的所有线程,并重置为初始值。
有两个构造方法,其中一个构造方法可以指定每次最后一个线程,需要执行的额外任务。
cyclicBarrier.reset() 用于提前唤醒被阻塞的线程,并重置为初始值 )
(原子变量类) AtomicInteger 一般用于无锁进行自增计数情形
(锁) volatile + (ReentrantLock + Condition) / synchronized
通过 condition.await()/condition.signal() 或者 object.wait()/object.notify() 的 挂起/通知机制 来完成线程协作。
1.凡是可以用semaphore解决的问题,大多都可以使用管程(也就是lock)来解决,但使用lock需要增加一个变量来标记起始条件.
该变量的作用:决定哪一个线程先执行第一次,其他的线程此时应当阻塞或者挂起。
2.凡是可以使用多个condition可以解决的问题,都可以使用一个condition和一个volatile变量来解决
一个condition,在唤起的时候,只能调用 notifyAll()。此时这个volatile变量将用于判断被唤醒的线程中,哪些线程是我们期望接下来继续执行的;而其余的线程应当再次被挂起。
实现1:信号量 + Atomic(计数)
class H2O {
// Initialize hydrogen group (H20) limit.限制了最多可执行2次
private Semaphore semaH = new Semaphore(2);
// Initialize oxygen group (H2O) limit.限制了最多可执行1次
private Semaphore semaO = new Semaphore(1);
// Initialize group count.记录每一次生成水分子的进度
private AtomicInteger groupCount = new AtomicInteger(0);
private static final int GROUP_H_LIMIT = 2;
private static final int GROUP_O_LIMIT = 1;
private static final int GROUP_TOTAL_LIMIT = GROUP_H_LIMIT + GROUP_O_LIMIT;
public H2O() {
}
public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
// Try to acquire hygrogen permit.
this.semaH.acquire(1);
// releaseHydrogen.run() outputs "H". Do not change or remove this line.
releaseHydrogen.run();
// Increment group molecule count.
this.groupCount.incrementAndGet();
//检查是否已生成了一个完整的水分子
resetIfNeeded();
}
public void oxygen(Runnable releaseOxygen) throws InterruptedException {
this.semaO.acquire(1);
// releaseOxygen.run() outputs "O". Do not change or remove this line.
releaseOxygen.run();
this.groupCount.incrementAndGet();
//检查是否已生成了一个完整的水分子
resetIfNeeded();
}
//只有这个方法,会给两个信号量增加许可数
private void resetIfNeeded() {
// If the current group is ready, release permits and try another.
if (this.groupCount.compareAndSet(GROUP_TOTAL_LIMIT, 0)) {
this.semaH.release(GROUP_H_LIMIT);
this.semaO.release(GROUP_O_LIMIT);
}
}
}
实现2:信号量 + CyclicBarrier (计数)
class H2O {
//只要CyclicBarrier达到计数值3,就执行semaphoreH和semaphoreO许可证颁发
private CyclicBarrier barrier = new CyclicBarrier(3, new Runnable() {
@Override
public void run() {
semaphoreH.release(2);
semaphoreO.release();
}
});
private Semaphore semaphoreH;
private Semaphore semaphoreO;
public H2O() {
//确保H至多执行2次,O至多执行1次
semaphoreH = new Semaphore(2);
semaphoreO = new Semaphore(1);
}
public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
//此处只消耗许可证,颁发许可证交由CyclicBarrier
semaphoreH.acquire();
// releaseHydrogen.run() outputs "H". Do not change or remove this line.
releaseHydrogen.run();
try {
//增加CyclicBarrier的计数
barrier.await();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
public void oxygen(Runnable releaseOxygen) throws InterruptedException {
//此处只消耗许可证,颁发许可证交由CyclicBarrier
semaphoreO.acquire();
// releaseOxygen.run() outputs "O". Do not change or remove this line.
releaseOxygen.run();
try {
//增加CyclicBarrier的计数
barrier.await();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
来源:oschina
链接:https://my.oschina.net/u/3858564/blog/3163205