CountDownLatch 闭锁
是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。
package study;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchTest {
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(5);
new Thread(new Server2(countDownLatch)).start();
for (int i = 0; i < 10; i++) {
new Thread(new Server(countDownLatch)).start();
}
}
}
class Server implements Runnable {
private CountDownLatch myCount;
public Server(CountDownLatch myCount) {
this.myCount = myCount;
}
@Override
public void run() {
//递减锁存器的计数,如果计数到达零,则释放所有等待的线程。如果当前计数大于零,则将计数减少.
myCount.countDown();
System.out.println("一个server1运行完了 还剩" + myCount.getCount());
}
}
class Server2 implements Runnable {
private CountDownLatch myCount;
public Server2(CountDownLatch myCount) {
this.myCount = myCount;
}
@Override
public void run() {
try {
System.out.println("正在等待N个server1运行完毕");
myCount.await();
System.out.println("N个server1运行完毕");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void countDown()
递减锁存器的计数,如果计数到达零,则释放所有等待的线程。如果当前计数大于零,则将计数减少.
public boolean await(long timeout,TimeUnit unit) throws InterruptedException
使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。如果当前计数为零,则此方法立刻返回true值。
CyclicBarrier 栅栏锁
CyclicBarrier可以使一定数量的线程反复地在栅栏位置处汇集。当线程到达栅栏位置时将调用await方法,这个方法将阻塞直到所有线程都到达栅栏位置。如果所有线程都到达栅栏位置,那么栅栏将打开,此时所有的线程都将被释放,而栅栏将被重置以便下次使。它可以使用reset()方法重置。
package study;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
@Override
public void run() {
System.out.println("所有线程已经结束");
}
});
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
new Thread(new Server(cyclicBarrier)).start();
} else {
new Thread(new Server2(cyclicBarrier)).start();
}
}
}
}
class Server implements Runnable {
CyclicBarrier cyclicBarrier;
public Server(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
System.out.println("一个server1到达栅栏");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
//如果一个线程处于等待状态时,如果其他线程调用reset(),或者调用的barrier原本就是被损坏的,则抛出BrokenBarrierException异常
e.printStackTrace();
}
}
}
class Server2 implements Runnable {
CyclicBarrier cyclicBarrier;
public Server2(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
System.out.println("一个server2到达栅栏");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
//如果一个线程处于等待状态时,如果其他线程调用reset(),或者调用的barrier原本就是被损坏的,则抛出BrokenBarrierException异常
e.printStackTrace();
}
}
}
输出结果会有两组 说明了CyclicBarrier是可以复用的。
注意:这几种情况 所有的CyclicBarrier阻塞的线程全部会被唤醒往下走
最后一个线程到达,即index == 0
某个参与线程等待超时
某个参与线程被中断
调用了CyclicBarrier的reset()方法
当有任何一个线程中断了,非正常运行完,会抛出异常并唤醒其他线程,其他线程醒来后,也会抛出异常。CyclicBarrier处于损坏状态
交换机:两个线程运行到某处可以交换对象 运用场景比较少
public class TestExchanger {
public static void main(String[] args) {
Exchanger exchanger = new Exchanger();
ExchangerRunnable exchangerRunnable1 =
new ExchangerRunnable(exchanger, "A");
ExchangerRunnable2 exchangerRunnable2 =
new ExchangerRunnable2(exchanger, "B");
new Thread(exchangerRunnable1).start();
new Thread(exchangerRunnable2).start();
}
}
class ExchangerRunnable implements Runnable {
Exchanger exchanger = null;
Object object = null;
public ExchangerRunnable(Exchanger exchanger, Object object) {
this.exchanger = exchanger;
this.object = object;
}
@Override
public void run() {
Object previous = this.object;
try {
System.out.println("进入1");
this.object = this.exchanger.exchange(this.object);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " exchanged " + previous + " for " + this.object);
}
}
class ExchangerRunnable2 implements Runnable {
Exchanger exchanger = null;
Object object = null;
public ExchangerRunnable2(Exchanger exchanger, Object object) {
this.exchanger = exchanger;
this.object = object;
}
@Override
public void run() {
Object previous = this.object;
try {
//这里会睡眠10s 那么线程1也因此被阻塞10s
Thread.sleep(10000);
System.out.println("进入2");
this.object = this.exchanger.exchange(this.object);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " exchanged " + previous + " for " + this.object);
}
}