前言
简单记录自己平常写代码的case, 写代码最重要的就是学习思想,欢迎讨论。
CountDownLatch
多线程交互中用的最多的就是CountDownLatch, 可以根据源码单步调试一下,提高自己的阅读源码的能力。
场景:电影院看电影散场,一共六个人观看,管理员在电影播放完毕,游客散去以后关闭影院大门。
public static void main(String[] args) throws Exception{
CountDownLatch countDownLatch = new CountDownLatch(6);
// 模拟6个游客在影院看电影
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "离开影院");
// 走一个人,countDownLatch减少1,直到变为零
countDownLatch.countDown();
}, String.valueOf(i)).start();
}
System.out.println("管理员" + Thread.currentThread().getName() + "等待关门");
// 管理员时刻监控countDownLatch的值,变为零的时候证明游客已全部离开
countDownLatch.await();
System.out.println("管理员" + Thread.currentThread().getName() + "关门成功");
}
CyclicBarrier
场景:相比于CountDownLatch, CyclicBarrier要表达的是,类似于坐过山车,一共有十个位置,直到人凑齐了,这辆过山车才会启动。(商家为了赚钱规定只有坐满人才发动过山车)
/*demo1*/
public static void main(String[] args) {
// 模拟3个线程到达屏障点,才触发一次屏障操作
// 第二个参数设置的是当有3个线程准备好的时候,要触发的屏障操作
CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {
System.out.println(Thread.currentThread().getName() + "触发一次屏障操作");
});
for (int i = 0; i < 9; i++) {
final int tempInt = i;
// 模拟线程准备时间(doSomething()...)
try {
TimeUnit.SECONDS.sleep(tempInt);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
System.out.println("线程" + tempInt + "准备就绪");
try {
// 等待其他线程准备就绪
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
}, String.valueOf(i)).start();
}
}
/*demo2*/
public static void main(String[] args) {
// 模拟3个线程到达屏障点(准备完毕)才触发一次屏障(过山车)操作
// 和上个CyclicBarrier的demo不同的是,第二个参数不设置
CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
for (int i = 0; i < 9; i++) {
final int tempInt = i;
// 模拟线程准备时间
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(tempInt);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + tempInt + "准备完成");
try {
// 当返回参数为零时,表示满足触发屏障条件
if (cyclicBarrier.await() == 0) {
// 最后一个到达屏障点的线程进行屏障操作
System.out.println("线程" + Thread.currentThread().getName() + "触发屏障操作");
}
} catch (Exception e) {
e.printStackTrace();
}
}, String.valueOf(i)).start();
}
}
Semaphore
场景:例如去商场买衣服,去试衣间试衣服,一共有五个试衣间,进去试衣间,把门锁上,试衣服,试完后,打开门出来。别人可以接着用这个试衣间(试衣间可以看做共享资源,同时只能有一个人占有)
public static void main(String[] args) {
// 默认为非公平的获取方式
// 例如去商场买衣服,去试衣间试衣服,一共有五个试衣间,当参数为true时,表示使用先进先出的FIFO算法保证先acquire的线程先获取许可进入
// 当参数为false时,表示线程可以加塞到先获取acquire的线程钱获取许可
Semaphore semaphore = new Semaphore(5, true);
// 假如有十个人要试衣服,使用商场公有的试衣间
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "同学进入试衣间成功!!!");
try {
// 模拟某个同学占用了试衣间多久时间
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "同学离开试衣间!!!");
semaphore.release();
}, String.valueOf(i)).start();
}
}
有哪里不对的指出来,大家共同进步。