序言
多线程的使用是开发极其重要的一环,本篇文章介绍三种方式,让线程循环打印ABC,其中涉及JUC下面的三个重要工具类。
Semaphore实现
package org.example.exercise;
import java.util.concurrent.Semaphore;
public class TestWeiLai1 {
public static void main(String[] args) {
Semaphore aSemaphore = new Semaphore(1);
Semaphore bSemaphore = new Semaphore(0);
Semaphore cSemaphore = new Semaphore(0);
new Thread(new MyRunnable(aSemaphore, bSemaphore, "A")).start();
new Thread(new MyRunnable(bSemaphore, cSemaphore, "B")).start();
new Thread(new MyRunnable(cSemaphore, aSemaphore, "C")).start();
}
static class MyRunnable implements Runnable {
private final Semaphore current;
private final Semaphore next;
private final String str;
public MyRunnable(Semaphore current, Semaphore next, String str) {
this.current = current;
this.next = next;
this.str = str;
}
@Override
public void run() {
try {
for (int i = 0;i < 3;i++) {
current.acquire();
System.out.println(str);
next.release();
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
CyclicBarrier实现
package org.example.exercise;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class TestWeiLai2 {
private static int count = 0;
private static final String arr = "ABC";
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {
});
Runnable runnable = () -> {
for (int i = 0;i < 3;i++) {
count = count > 2 ? 0 : count;
synchronized (TestWeiLai2.class) {
System.out.println(arr.charAt(count++));
}
try {
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
throw new RuntimeException(e);
}
}
};
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
}
}
CountDownLatch实现
package org.example.exercise;
import java.util.concurrent.CountDownLatch;
public class TestWeiLai3 {
static CountDownLatch countDownLatchA = new CountDownLatch(1);
static CountDownLatch countDownLatchB = new CountDownLatch(1);
static CountDownLatch countDownLatchC = new CountDownLatch(1);
public static void main(String[] args) {
new Thread(() -> {
for (int i = 0;i < 3;i++) {
try {
countDownLatchA.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("A");
countDownLatchA = new CountDownLatch(1);
countDownLatchB.countDown();
}
}).start();
new Thread(() -> {
for (int i = 0;i < 3;i++) {
try {
countDownLatchB.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("B");
countDownLatchB = new CountDownLatch(1);
countDownLatchC.countDown();
}
}).start();
new Thread(() -> {
for (int i = 0;i < 3;i++) {
try {
countDownLatchC.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("C");
countDownLatchC = new CountDownLatch(1);
countDownLatchA.countDown();
}
}).start();
countDownLatchA.countDown();
}
}
总结
从上述三种方式可以看到三种方式实现各不相同,具体如下
- Semaphore实现主要是通过获取信号量、释放信号量构建线程之前的同步循环
- CyclicBarrier是使用它的特性,当所有线程都到屏障时才结束等待,同时用锁对共享计数器递增,从而实现循环打印
- CountDownLatch较为复杂,由于其只能减而不能增,因此无法封装一个统一的方法进行操作,需要对原有变量更改,所以需要使用完之后,new新的实例给原有变量,从而构建线程之间的同步循环,实现循环打印
评论