• 线程通信的4种方式


     

     

    线程通信常用的方式有:

    • wait/notify 等待
    • Volatile 内存共享
    • CountDownLatch 并发工具
    • CyclicBarrier 并发工具

    wait/notify

    两个线程交替打印奇偶数,通过wait/notify实现

    public class WaitNotify {
      // 状态锁
      private static Object lock = new Object();
      private static Integer i = 0;
    
      public void odd() {
        while (i < 10) {
          synchronized (lock) {
            if (i % 2 == 1) {
              System.out.println(Thread.currentThread().getName() + " - " + i);
              try {
                Thread.sleep(1000);
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
              i++;
              lock.notify();
            } else {
              try {
                lock.wait();
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
            }
          }
        }
      }
    
      public void even() {
        while (i < 10) {
          synchronized (lock) {
            if (i % 2 == 0) {
              System.out.println(Thread.currentThread().getName() + " - " + i);
              try {
                Thread.sleep(1000);
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
              i++;
              lock.notify();
            } else {
              try {
                lock.wait();
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
            }
          }
        }
      }
    
      public static void main(String[] args) {
    
        WaitNotify waitNotify = new WaitNotify();
    
        Thread t1 = new Thread(() -> waitNotify.odd(), "线程1");
        Thread t2 = new Thread(() -> waitNotify.even(), "线程2");
    
        t1.start();
        t2.start();
      }
    }
    

    结果:

    线程2 - 0
    线程1 - 1
    线程2 - 2
    线程1 - 3
    线程2 - 4
    线程1 - 5
    线程2 - 6
    线程1 - 7
    线程2 - 8
    线程1 - 9
    线程2 - 10
    

    Volatile

    volatile 修饰内存可见性

    public class Volatile implements Runnable {
      private static volatile Boolean flag = true;
    
      @Override
      public void run() {
        while (flag) {
          System.out.println(Thread.currentThread().getName() + " - 执行");
        }
        System.out.println("线程结束");
      }
    
      public static void main(String[] args) {
        Thread t = new Thread(new Volatile());
        t.start();
        try {
          Thread.sleep(5);
          flag = false;
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
    

    结果:

    Thread-0 - 执行
    Thread-0 - 执行
    Thread-0 - 执行
    Thread-0 - 执行
    Thread-0 - 执行
    线程结束
    

    CountDownLatch

    CountDownLatch可以代替wait/notify的使用,并去掉synchronized,下面重写第一个例子:

    import java.util.concurrent.CountDownLatch;
    
    public class CountDown {
      private static Integer i = 0;
      final static CountDownLatch countDown = new CountDownLatch(1);
    
      public void odd() {
        while (i < 10) {
          if (i % 2 == 1) {
            System.out.println(Thread.currentThread().getName() + " - " + i);
            try {
              Thread.sleep(1000);
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
            i++;
            countDown.countDown();
          } else {
            try {
              countDown.await();
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
          }
        }
      }
    
      public void even() {
        while (i < 10) {
          if (i % 2 == 0) {
            System.out.println(Thread.currentThread().getName() + " - " + i);
            try {
              Thread.sleep(1000);
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
            i++;
            countDown.countDown();
          } else {
            try {
              countDown.await();
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
          }
        }
      }
    
      public static void main(String[] args) {
    
        CountDown countDown = new CountDown();
    
        Thread t1 = new Thread(() -> countDown.odd(), "线程1");
        Thread t2 = new Thread(() -> countDown.even(), "线程2");
    
        t1.start();
        t2.start();
      }
    }
    
    

    CyclicBarrier

    等待N个线程都达到某个状态后继续运行

    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    
    public class CyclicBarrierTest {
      public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
        new Thread(() -> {
          System.out.println(Thread.currentThread().getName() + ": 准备...");
          try {
            cyclicBarrier.await();
          } catch (InterruptedException e) {
            e.printStackTrace();
          } catch (BrokenBarrierException e) {
            e.printStackTrace();
          }
          System.out.println("全部启动完毕!");
        }, "线程1").start();
    
        new Thread(() -> {
          System.out.println(Thread.currentThread().getName() + ": 准备...");
          try {
            cyclicBarrier.await();
          } catch (InterruptedException e) {
            e.printStackTrace();
          } catch (BrokenBarrierException e) {
            e.printStackTrace();
          }
          System.out.println("全部启动完毕!");
        }, "线程2").start();
    
        new Thread(() -> {
          System.out.println(Thread.currentThread().getName() + ": 准备...");
          try {
            cyclicBarrier.await();
          } catch (InterruptedException e) {
            e.printStackTrace();
          } catch (BrokenBarrierException e) {
            e.printStackTrace();
          }
          System.out.println("全部启动完毕!");
        }, "线程3").start();
      }
    }
    

    结果:

    线程3: 准备...
    线程2: 准备...
    线程1: 准备...
    全部启动完毕!
    全部启动完毕!
    全部启动完毕!
    

    参考资料

  • 相关阅读:
    1360 奇怪的电梯(lift)
    1249 Lake Counting
    1330 【例8.3】最少步数
    1329 【例8.2】细胞
    1215 迷宫
    垃圾树
    vector
    1970:【15NOIP普及组】扫雷游戏
    1251:仙岛求药
    Python3+PCAN-USB基于PCAN-Basic二次开发实现上位机功能
  • 原文地址:https://www.cnblogs.com/linyufeng/p/9671844.html
Copyright © 2020-2023  润新知