多线程交替打印的几种解法

常见解法:
1. synchronized+wait/notify
2. join()
3. 自旋+volatile
4. Lock
5. Lock+Condition
6. Semaphore

1. synchronized 关键字

//一个线程打印1~ 52,另一个线程打印A~Z,打印顺序是12A34B…5152Z
public class TakeTurnsPrint {
    private boolean flag;
    private int count;

    public synchronized void printNum() {
        for (int i = 0; i < 26; i++) {
            //虚假唤醒”(spurious wakeup)的问题,线程可能在既没有被notify/notifyAll,也没有被中断或者超时的情况下被唤醒,这种唤醒是我们不希望看到的
            //这样即便被虚假唤醒了,也会再次检查while里面的条件,如果不满足条件,就会继续wait
            while (flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            flag = !flag;
            System.out.print(++count);
            System.out.print(++count);
            notify();
        }
    }

    public synchronized void printLetter() {
        for (int i = 0; i < 26; i++) {
            while (!flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            flag = !flag;
            System.out.print((char) (65 + i));
            notify();
        }
    }

    public static void main(String[] args) {
        TakeTurnsPrint turnsPrint = new TakeTurnsPrint();
        new Thread(() -> turnsPrint.printNum()).start();
        new Thread(() -> turnsPrint.printLetter()).start();
    }
}

2. Lock 显式锁

3. semaphore 信号量

信号量是信号量,和线程没有关系
信号量与特定的资源一一对应,即1个信号量一定是控制一个资源的。
信号量, 可以用来控制当下可访问特定资源的线程数量;
a.acquire() 线程获取一个a信号量的令牌 a-1
b.release() b信号量增加一个令牌,唤醒一个获取令牌不成功的阻塞线程b+1

// 三个线程循环依次打印ABC
public class TakeTurnsPrint_Semaphore {
  Semaphore a= new Semaphore(1);
  Semaphore b= new Semaphore(0);
  Semaphore c= new Semaphore(0);
  void printA() {
      try {
          for (int i = 0; i < 10; i++) {
              a.acquire();
              System.out.println(Thread.currentThread().getName());
              b.release();
          }
      } catch (InterruptedException e) {
          e.printStackTrace();
      }
  }
  void printC() {
      try {
          for (int i = 0; i < 10; i++) {
              c.acquire();
              System.out.println(Thread.currentThread().getName());
              a.release();
          }
      } catch (InterruptedException e) {
          e.printStackTrace();
      }
  }
  void printB() {
      try {
          for (int i = 0; i < 10; i++) {
              b.acquire();
              System.out.println(Thread.currentThread().getName());
              c.release();
          }
      } catch (InterruptedException e) {
          e.printStackTrace();
      }
  }

  public static void main(String[] args) {
      TakeTurnsPrint_Semaphore t=new TakeTurnsPrint_Semaphore();
      new Thread(()->t.printA(),"A").start();
      new Thread(()->t.printB(),"B").start();
      new Thread(()->t.printC(),"C").start();
  }
}
posted @ 2022-07-12 14:42  空中行走的鱼  阅读(84)  评论(0)    收藏  举报