Java 多线程交替打印
目录
题目
使用三个线程 T1、T2、T3,如何让他们按顺序交替打印 10 次 A B C。
方案一:synchronized
public class SynchronizedLockPrinter { static class Printer { private final Object lock = new Object(); private int count = 0; public void print(int n, int target, char content) { for (int i = 0; i < n; ) { synchronized (lock) { while (count % 3 != target) { try { lock.wait(); } catch (Exception e) { System.out.println(e); } } System.out.print(content); count++; i++; lock.notifyAll(); } } } public void print() { new Thread(()-> {print(10, 0, 'A');}).start(); new Thread(()-> {print(10, 1, 'B');}).start(); new Thread(()-> {print(10, 2, 'C');}).start(); } } public static void main(String [] args) { new Printer().print(); } }
注意,这里需要通过 volatile 关键自
方法二:ReentrantLock
public class SignalLockPrinter { static class Printer { private final Lock lock = new ReentrantLock(); private volatile int count = 0; public void print(int n, int target, char content) { for (int i = 0; i < n; ) { lock.lock(); try { while (count % 3 == target) { System.out.print(content); count++; i++; } } catch (Exception e) { System.out.println(e); } finally { lock.unlock(); } } } public void print() { new Thread(()-> {print(10, 0, 'A');}).start(); new Thread(()-> {print(10, 1, 'B');}).start(); new Thread(()-> {print(10, 2, 'C');}).start(); } } public static void main(String [] args) { new Printer().print(); } }
方法三:ReentrantLock + Condition(非公平锁)
public class UnfairLockConditionPrinter { static class ConditionPrinter { private final Lock lock = new ReentrantLock(); // 非公平锁 private volatile int count = 0; private final int threadNumber = 10; private final Condition condition1 = lock.newCondition(); private final Condition condition2 = lock.newCondition(); private final Condition condition3 = lock.newCondition(); public void print(int target, String content, Condition current, Condition next) { for (int i = 0; i < threadNumber; i++) { lock.lock(); try { // 执行临界区代码前判断:防止锁被不满足条件的线程抢占 while (count % 3 != target) { current.await(); // 条件等待并释放锁 } System.out.print(content); count++; // 注意:这不是一个原子操作 next.signal(); // 唤醒一个等待该条件的线程 } catch (Exception e) { System.out.println(e); } finally { lock.unlock(); } } } public void print() { new Thread(() -> {print(0, "A", condition1, condition2);}).start(); new Thread(() -> {print(1, "B", condition2, condition3);}).start(); new Thread(() -> {print(2, "C", condition3, condition1);}).start(); } } public static void main(String[] args) { new ConditionPrinter().print(); } }
注意,
-
unlock()
并不会阻塞当前线程,所以,当 A 线程在释放锁后,线程状态并没有改变,所以 A 线程还会去尝试获取一次锁,如果获取锁失败,就会进入阻塞状态;如果获取成功,就会进入条件等待状态。 -
count++
不是一个原子操作,但是由于同时只有一个线程在执行,所以结果是正确的。实际使用的时候,可以替换为
LongAdder
、AtomicInteger
等原子类。
优化:改成公平锁,可以减少锁的竞争程度。
方法四:ReentrantLock + Condition(公平锁)
public class FairLockConditionPrinter { static class ConditionPrinterEnhance { private final Lock lock = new ReentrantLock(true); private final Condition condition = lock.newCondition(); private volatile int count = 0; private final int threadNumber = 10; public void print(int target, char content) { lock.lock(); try { for (int i = 0; i < threadNumber; i++) { while (count % 3 != target) { condition.await(); } System.out.println(Thread.currentThread().getName() + ": " + content + " " + count); count++; condition.signal(); } } catch (Exception e) { System.out.println(e); } finally { lock.unlock(); } } public void print() { char content = 'A'; for (int i = 0; i < 3; i++) { final int k = i; new Thread(() -> print( k, (char) (content + k))).start(); } } } public static void main(String[] args) { new ConditionPrinterEnhance().print(); } }
或者
public class Test { private static Lock lock = new ReentrantLock(); private static Condition c1 = lock.newCondition(); private static Condition c2 = lock.newCondition(); private static Condition c3 = lock.newCondition(); private void printABC(Condition currentThread, Condition nextThread) { for (int i = 0; i < 10; i++) { lock.lock(); try { System.out.print(Thread.currentThread().getName()); nextThread.signal(); //唤醒下一个线程,而不是唤醒所有线程 currentThread.await(); // 可以在最后一个线程执行的时候,跳过不等待,避免最后一个线程执行完后挂起 } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } } public static void main(String[] args) { Test print = new Test(); new Thread(() -> { print.printABC(c1, c2); }, "A").start(); new Thread(() -> { print.printABC(c2, c3); }, "B").start(); new Thread(() -> { print.printABC(c3, c1); }, "C").start(); } }
方法五:Semaphore
public class SemaphorePrinter { static class Printer { private final int n = 10; private final Semaphore s1 = new Semaphore(1); private final Semaphore s2 = new Semaphore(0); private final Semaphore s3 = new Semaphore(0); private void print(char content, Semaphore current, Semaphore next) { for (int i = 0; i < n; i++) { try { current.acquire(); System.out.print(content); next.release(); } catch (Exception e) { System.out.println(e); } } } public void print() { new Thread(() -> {print('A', s1, s2);}).start(); new Thread(() -> {print('B', s2, s3);}).start(); new Thread(() -> {print('C', s3, s1);}).start(); } } public static void main(String [] args) { new Printer().print(); } }
本文作者:LARRY1024
本文链接:https://www.cnblogs.com/larry1024/p/17986059
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步