• 线程通信的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: 准备...
    全部启动完毕!
    全部启动完毕!
    全部启动完毕!
    

    参考资料

  • 相关阅读:
    Spring之循环依赖与解决方案
    ipv4+ipv6网络中的DDNS
    NAT、PAT、DMZ、端口映射、端口转发、UPNP
    如何实现内外网或多网络环境下上网?路由route
    局域网学习MAC地址?ping+arp
    网络故障排查?ping和trace*
    有了MAC地址,为什么还要用IP地址?
    Nginx原理解析
    磁盘io
    last总结
  • 原文地址:https://www.cnblogs.com/linyufeng/p/9671844.html
Copyright © 2020-2023  润新知