3个线程,按顺序打印A,B,C,一共打印100个字符串
准备:定义使用的枚举
/**
* 符号枚举
*
* @author Administrator
*/
public enum SignEnum {
/**/
A {
@Override
public SignEnum last() {
return C;
}
},
B {
@Override
public SignEnum last() {
return A;
}
},
C {
@Override
public SignEnum last() {
return B;
}
};
/**
* 上一个符号
*
* @return 符号
*/
public abstract SignEnum last();
}
有锁操作
使用线程通信
1:Object 的 wait / notifyAll
/**
* 通过wait/notify打印
*
* @author Administrator
*/
public class WaitNotifyTest {
/**
* 锁
*/
private final Object lock = new Object();
/**
* 当前符号
*/
private volatile SignEnum currentSign = SignEnum.C;
/**
* 自定义线程池
*/
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
Runtime.getRuntime().availableProcessors() * 2, 5, TimeUnit.MINUTES,
new LinkedBlockingQueue<>(3), Thread::new, new ThreadPoolExecutor.AbortPolicy());
/**
* 打印
*/
@Test
@SneakyThrows
public void testPrint() {
// 打印B
Future<?> bFuture = executor.submit(() -> doPrint(33, SignEnum.B));
// 打印A
Future<?> aFuture = executor.submit(() -> doPrint(34, SignEnum.A));
// 打印C
Future<?> cFuture = executor.submit(() -> doPrint(33, SignEnum.C));
// 等待打印完成
while (!aFuture.isDone() || !bFuture.isDone() || !cFuture.isDone()) {
TimeUnit.MILLISECONDS.sleep(5);
}
// 关闭线程池
executor.shutdown();
}
/**
* 执行打印
*
* @param count 次数
* @param targetSign 目标符号
*/
@SneakyThrows
private void doPrint(int count, SignEnum targetSign) {
synchronized (lock) {
for (int index = 0; index < count; index++) {
// 如果当前符号为目标符号的上一个符号,执行打印符号
if (Objects.equals(targetSign.last(), currentSign)) {
// 打印目标符号
System.out.print(targetSign.name());
// 打印分割符,方便观察
if (Objects.equals(SignEnum.C, targetSign)) {
System.out.print("|");
}
// 切换当前符号
currentSign = targetSign;
// 释放锁,通知其他线程
// 不能使用notify,如果通知的某个线程不符合条件,进行等待,将会造成程序阻塞
lock.notifyAll();
}
// 不匹配的话,index回退,同时进行等待
else {
index--;
lock.wait();
}
}
}
}
}
输出
2:Condition 的 await / signalAll
/**
* 通过condition打印
*
* @author Administrator
*/
public class ConditionTest {
/**
* 锁
*/
private final Lock lock = new ReentrantLock();
/**
* 条件
*/
private final Condition condition = lock.newCondition();
/**
* 当前符号
*/
private volatile SignEnum currentSign = SignEnum.C;
/**
* 自定义线程池
*/
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
Runtime.getRuntime().availableProcessors() * 2, 5, TimeUnit.MINUTES,
new LinkedBlockingQueue<>(3), Thread::new, new ThreadPoolExecutor.AbortPolicy());
/**
* 打印
*/
@Test
@SneakyThrows
public void testPrint() {
// 打印B
Future<?> bFuture = executor.submit(() -> doPrint(33, SignEnum.B));
// 打印A
Future<?> aFuture = executor.submit(() -> doPrint(34, SignEnum.A));
// 打印C
Future<?> cFuture = executor.submit(() -> doPrint(33, SignEnum.C));
// 等待打印完成
while (!aFuture.isDone() || !bFuture.isDone() || !cFuture.isDone()) {
TimeUnit.MILLISECONDS.sleep(5);
}
// 关闭线程池
executor.shutdown();
}
/**
* 执行打印
*
* @param count 次数
* @param targetSign 目标符号
*/
private void doPrint(int count, SignEnum targetSign) {
lock.lock();
try {
for (int index = 0; index < count; index++) {
// 如果当前符号为目标符号的上一个符号,执行打印符号
if (Objects.equals(targetSign.last(), currentSign)) {
// 打印目标符号
System.out.print(targetSign.name());
// 打印分割符,方便观察
if (Objects.equals(SignEnum.C, targetSign)) {
System.out.print("|");
}
// 切换当前符号
currentSign = targetSign;
// 释放锁,通知其他线程
// 不能使用signal,如果通知的某个线程不符合条件,进行等待,将会造成程序阻塞
condition.signalAll();
}
// 不匹配的话,index回退,同时进行等待
else {
index--;
condition.await();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
输出
不使用线程通信
1.Semaphore
/**
* 通过Semaphore打印
*
* @author Administrator
*/
public class SemaphoreTest {
/**
* 当前符号
*/
private volatile SignEnum currentSign = SignEnum.C;
/**
* 信号量
*/
private final Semaphore semaphore = new Semaphore(1);
/**
* 自定义线程池
*/
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
Runtime.getRuntime().availableProcessors() * 2, 5, TimeUnit.MINUTES,
new LinkedBlockingQueue<>(3), Thread::new, new ThreadPoolExecutor.AbortPolicy());
/**
* 打印
*/
@Test
@SneakyThrows
public void testPrint() {
// 打印B
Future<?> bFuture = executor.submit(() -> doPrint(33, SignEnum.B));
// 打印A
Future<?> aFuture = executor.submit(() -> doPrint(34, SignEnum.A));
// 打印C
Future<?> cFuture = executor.submit(() -> doPrint(33, SignEnum.C));
// 等待打印完成
while (!aFuture.isDone() || !bFuture.isDone() || !cFuture.isDone()) {
TimeUnit.MILLISECONDS.sleep(5);
}
// 关闭线程池
executor.shutdown();
}
/**
* 执行打印
*
* @param count 次数
* @param targetSign 目标符号
*/
@SneakyThrows
private void doPrint(int count, SignEnum targetSign) {
for (int index = 0; index < count; index++) {
// 尝试获取令牌,与锁的效果类似
if (semaphore.tryAcquire()) {
try {
// 如果当前符号为目标符号的上一个符号,执行打印符号
if (Objects.equals(targetSign.last(), currentSign)) {
// 打印目标符号
System.out.print(targetSign.name());
// 打印分割符,方便观察
if (Objects.equals(SignEnum.C, targetSign)) {
System.out.print("|");
}
// 切换当前符号+
currentSign = targetSign;
}
// 不匹配的话,index回退
else {
index--;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放令牌
semaphore.release();
}
}
// 获取不到令牌,index回退
else {
index--;
}
}
}
}
输出
无锁操作
使用线程通信
1.LockSupport 的 park / unpark
/**
* 通过LockSupport打印
*
* @author Administrator
*/
public class LockSupportTest {
/**
* 当前符号
*/
private volatile SignEnum currentSign = SignEnum.C;
/**
* 线程集合
*/
private final List<Thread> threadList = new ArrayList<>(3);
/**
* 自定义线程池
*/
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
Runtime.getRuntime().availableProcessors() * 2, 5, TimeUnit.MINUTES,
new LinkedBlockingQueue<>(3), r -> {
Thread thread = new Thread(r);
threadList.add(thread);
return thread;
}, new ThreadPoolExecutor.AbortPolicy());
/**
* 打印
*/
@Test
@SneakyThrows
public void testPrint() {
// 打印B
Future<?> bFuture = executor.submit(() -> doPrint(33, SignEnum.B));
// 打印A
Future<?> aFuture = executor.submit(() -> doPrint(34, SignEnum.A));
// 打印C
Future<?> cFuture = executor.submit(() -> doPrint(33, SignEnum.C));
// 等待打印完成
while (!aFuture.isDone() || !bFuture.isDone() || !cFuture.isDone()) {
TimeUnit.MILLISECONDS.sleep(5);
}
// 关闭线程池
executor.shutdown();
}
/**
* 执行打印
*
* @param count 次数
* @param targetSign 目标符号
*/
@SneakyThrows
private void doPrint(int count, SignEnum targetSign) {
// 不能使用锁,unpark方法不会将锁释放,造成程序阻塞
for (int index = 0; index < count; index++) {
// 如果当前符号为目标符号的上一个符号,执行打印符号
if (Objects.equals(targetSign.last(), currentSign)) {
// 打印目标符号
System.out.print(targetSign.name());
// 打印分割符,方便观察
if (Objects.equals(SignEnum.C, targetSign)) {
System.out.print("|");
}
// 切换当前符号
currentSign = targetSign;
// 通知其他线程
Thread currentThread = Thread.currentThread();
threadList.forEach(thread -> {
if (!Objects.equals(currentThread, thread)) {
LockSupport.unpark(thread);
}
});
}
// 不匹配的话,index回退,同时进行等待
else {
index--;
LockSupport.park();
}
}
}
}
输出
不使用线程通信
1.CyclicBarrier结合AtomicInteger
/**
* 通过CyclicBarrier打印
*
* @author Administrator
*/
public class CyclicBarrierTest {
/**
* 当前符号
*/
private volatile SignEnum currentSign = SignEnum.C;
/**
* 计数器
*/
private final AtomicInteger atomicInteger = new AtomicInteger();
/**
* 篱栅
*/
private final CyclicBarrier cyclicBarrier = new CyclicBarrier(3, atomicInteger::incrementAndGet);
/**
* 自定义线程池
*/
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
Runtime.getRuntime().availableProcessors() * 2, 5, TimeUnit.MINUTES,
new LinkedBlockingQueue<>(3), Thread::new, new ThreadPoolExecutor.AbortPolicy());
/**
* 打印
*/
@Test
@SneakyThrows
public void testPrint() {
// 打印B
executor.execute(() -> doPrint(33, SignEnum.B));
// 打印A
executor.execute(() -> doPrint(34, SignEnum.A));
// 打印C
executor.execute(() -> doPrint(33, SignEnum.C));
// 等待打印完成
while (atomicInteger.get() != 34) {
TimeUnit.MILLISECONDS.sleep(5);
}
// 关闭线程池
executor.shutdown();
}
/**
* 执行打印
*
* @param count 次数
* @param targetSign 目标符号
*/
@SneakyThrows
private void doPrint(int count, SignEnum targetSign) {
for (int index = 0; index < count; index++) {
// 如果当前符号为目标符号的上一个符号,执行打印符号
if (Objects.equals(targetSign.last(), currentSign)) {
// 打印目标符号
System.out.print(targetSign.name());
// 打印分割符,方便观察
if (Objects.equals(SignEnum.C, targetSign)) {
System.out.print("|");
}
// 切换当前符号
currentSign = targetSign;
// 阻塞等待
cyclicBarrier.await();
}
// 不匹配的话,index回退
else {
index--;
}
}
// B,C线程进行阻塞,保证cyclicBarrier走完,否则程序会阻塞
if (count == 33) {
cyclicBarrier.await();
}
}
}
输出
2.AtomicInteger
/**
* 通过AtomicInteger打印
*
* @author Administrator
*/
public class AtomicIntegerTest {
/**
* 当前符号
*/
private volatile SignEnum currentSign = SignEnum.C;
/**
* 计数器
*/
private final AtomicInteger counter = new AtomicInteger();
/**
* 自定义线程池
*/
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
Runtime.getRuntime().availableProcessors() * 2, 5, TimeUnit.MINUTES,
new LinkedBlockingQueue<>(3), Thread::new, new ThreadPoolExecutor.AbortPolicy());
/**
* 打印
*/
@Test
@SneakyThrows
public void testPrint() {
// 打印B
executor.execute(() -> doPrint(33, SignEnum.B));
// 打印A
executor.execute(() -> doPrint(34, SignEnum.A));
// 打印C
executor.execute(() -> doPrint(33, SignEnum.C));
// 等待打印完成
while (counter.get() != 100) {
TimeUnit.MILLISECONDS.sleep(5);
}
// 关闭线程池
executor.shutdown();
}
/**
* 执行打印
*
* @param count 次数
* @param targetSign 目标符号
*/
private void doPrint(int count, SignEnum targetSign) {
for (int index = 0; index < count; index++) {
// 如果当前符号为目标符号的上一个符号,执行打印符号
if (Objects.equals(targetSign.last(), currentSign)) {
// 打印目标符号
System.out.print(targetSign.name());
// 打印分割符,方便观察
if (Objects.equals(SignEnum.C, targetSign)) {
System.out.print("|");
}
// 切换当前符号
currentSign = targetSign;
// 计数+1
counter.incrementAndGet();
}
// 不匹配的话,index回退
else {
index--;
}
}
}
}
输出
3.CountDownLatch
/**
* 通过countDownLatch打印
*
* @author Administrator
*/
public class CountDownLatchTest {
/**
* 当前符号
*/
private volatile SignEnum currentSign = SignEnum.C;
/**
* 计数器
*/
private final CountDownLatch countDownLatch = new CountDownLatch(100);
/**
* 自定义线程池
*/
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
Runtime.getRuntime().availableProcessors() * 2, 5, TimeUnit.MINUTES,
new LinkedBlockingQueue<>(3), Thread::new, new ThreadPoolExecutor.AbortPolicy());
/**
* 打印
*/
@Test
@SneakyThrows
public void testPrint() {
// 打印B
executor.execute(() -> doPrint(33, SignEnum.B));
// 打印A
executor.execute(() -> doPrint(34, SignEnum.A));
// 打印C
executor.execute(() -> doPrint(33, SignEnum.C));
// 等待打印完成
countDownLatch.await();
// 关闭线程池
executor.shutdown();
}
/**
* 执行打印
*
* @param count 次数
* @param targetSign 目标符号
*/
@SneakyThrows
private void doPrint(int count, SignEnum targetSign) {
for (int index = 0; index < count; index++) {
// 如果当前符号为目标符号的上一个符号,执行打印符号
if (Objects.equals(targetSign.last(), currentSign)) {
try {
// 打印目标符号
System.out.print(targetSign.name());
// 打印分割符,方便观察
if (Objects.equals(SignEnum.C, targetSign)) {
System.out.print("|");
}
// 切换当前符号+
currentSign = targetSign;
} catch (Exception e) {
e.printStackTrace();
} finally {
// 计数减1
countDownLatch.countDown();
}
}
// 不匹配的话,index回退
else {
index--;
}
}
}
}
输出