固定运行顺序

wait-notify 实现

采用 wait-notify 机制可以实现对线程执行顺序的控制,我们只需要一个执行标志即可,如下代码所示:

  1. public class WaitNotify {
  2. // 用来同步的对象
  3. static Object obj = new Object();
  4. // t2 运行标记, 代表 t2 是否执行过
  5. static boolean t2runed = false;
  6. public static void main(String[] args) {
  7. Thread t1 = new Thread(() -> {
  8. synchronized (obj) {
  9. // 如果 t2 没有执行过
  10. while (!t2runed) {
  11. try {
  12. // t1 先等一会
  13. obj.wait();
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. }
  19. System.out.println(1);
  20. });
  21. Thread t2 = new Thread(() -> {
  22. System.out.println(2);
  23. synchronized (obj) {
  24. // 修改运行标记
  25. t2runed = true;
  26. // 通知 obj 上等待的线程(可能有多个,因此需要用 notifyAll)
  27. obj.notifyAll();
  28. }
  29. });
  30. t1.start();
  31. t2.start();
  32. }
  33. }

image.png

park-unpark 实现

  1. public class ParkUnpark {
  2. public static void main(String[] args) {
  3. Thread t1 = new Thread(() -> {
  4. LockSupport.park();
  5. System.out.println("1");
  6. }, "t1");
  7. Thread t2 = new Thread(() -> {
  8. System.out.println("2");
  9. LockSupport.unpark(t1);
  10. }, "t2");
  11. t1.start();
  12. t2.start();
  13. }
  14. }

image.png

交替运行顺序

要求依次“线程1输出a,线程2输出b,线程3输出c”,这样循环5次。即利用三个线程输出“abcabcabcabcabc”这样的结构。

wait-notify 实现

  1. public class SyncWaitNotify {
  2. private int flag;
  3. private final int loopNums;
  4. public SyncWaitNotify(int flag, int loopNums) {
  5. this.flag = flag;
  6. this.loopNums = loopNums;
  7. }
  8. @SneakyThrows
  9. public void print(int curFlag, int nextFlag, String content) {
  10. for (int i = 0; i < loopNums; i++) {
  11. synchronized (this) {
  12. //如果curFlag 和当前线程执行 flag 不相同
  13. while (this.flag != curFlag) {
  14. wait();
  15. }
  16. System.out.print(content);
  17. flag = nextFlag;
  18. notifyAll();
  19. }
  20. }
  21. }
  22. public static void main(String[] args) {
  23. SyncWaitNotify syncWaitNotify = new SyncWaitNotify(1, 5);
  24. //线程1打印 a -->flag=1
  25. new Thread(() -> {
  26. syncWaitNotify.print(1, 2, "a");
  27. }).start();
  28. //线程2打印 b -->flag=2
  29. new Thread(() -> {
  30. syncWaitNotify.print(2, 3, "b");
  31. }).start();
  32. //线程3打印 c -->flag=3
  33. new Thread(() -> {
  34. syncWaitNotify.print(3, 1, "c");
  35. }).start();
  36. }
  37. }

image.png

await-signal 实现

  1. public class AwaitSignal extends ReentrantLock {
  2. // 循环次数
  3. private final int loopNumber;
  4. public AwaitSignal(int loopNumber) {
  5. this.loopNumber = loopNumber;
  6. }
  7. public void start(Condition first) {
  8. this.lock();
  9. try {
  10. first.signal();
  11. } finally {
  12. this.unlock();
  13. }
  14. }
  15. public void print(String str, Condition current, Condition next) {
  16. for (int i = 0; i < loopNumber; i++) {
  17. this.lock();
  18. try {
  19. current.await();
  20. System.out.print(str);
  21. next.signal();
  22. } catch (InterruptedException e) {
  23. e.printStackTrace();
  24. } finally {
  25. this.unlock();
  26. }
  27. }
  28. }
  29. public static void main(String[] args) {
  30. AwaitSignal as = new AwaitSignal(5);
  31. //线程1的等待室
  32. Condition aWaitSet = as.newCondition();
  33. //线程2的等待室
  34. Condition bWaitSet = as.newCondition();
  35. //线程3的等待室
  36. Condition cWaitSet = as.newCondition();
  37. //线程1打印 a
  38. new Thread(() -> {
  39. as.print("a", aWaitSet, bWaitSet);
  40. }).start();
  41. //线程2打印 b
  42. new Thread(() -> {
  43. as.print("b", bWaitSet, cWaitSet);
  44. }).start();
  45. //线程3打印 c
  46. new Thread(() -> {
  47. as.print("c", cWaitSet, aWaitSet);
  48. }).start();
  49. //先唤醒 aWaitSet 中的线程1
  50. as.start(aWaitSet);
  51. }
  52. }

image.png

park-unpark 实现

  1. public class SyncPark {
  2. private final int loopNumber;
  3. private Thread[] threads;
  4. public SyncPark(int loopNumber) {
  5. this.loopNumber = loopNumber;
  6. }
  7. public void setThreads(Thread... threads) {
  8. this.threads = threads;
  9. }
  10. public void print(String str) {
  11. for (int i = 0; i < loopNumber; i++) {
  12. LockSupport.park();
  13. System.out.print(str);
  14. //输出str后,让下一个线程运行
  15. LockSupport.unpark(nextThread());
  16. }
  17. }
  18. private Thread nextThread() {
  19. Thread current = Thread.currentThread();
  20. int index = 0;
  21. for (int i = 0; i < threads.length; i++) {
  22. if (threads[i] == current) {
  23. index = i;
  24. break;
  25. }
  26. }
  27. if (index < threads.length - 1) {
  28. return threads[index + 1];
  29. } else {
  30. return threads[0];
  31. }
  32. }
  33. public void start() {
  34. for (Thread thread : threads) {
  35. thread.start();
  36. }
  37. //先让 threads[0] 执行
  38. LockSupport.unpark(threads[0]);
  39. }
  40. public static void main(String[] args) {
  41. SyncPark syncPark = new SyncPark(5);
  42. Thread t1 = new Thread(() -> {
  43. syncPark.print("a");
  44. });
  45. Thread t2 = new Thread(() -> {
  46. syncPark.print("b");
  47. });
  48. Thread t3 = new Thread(() -> {
  49. syncPark.print("c");
  50. });
  51. syncPark.setThreads(t1, t2, t3);
  52. syncPark.start();
  53. }
  54. }

image.png