線程通訊的4種方式

 

 

線程通訊經常使用的方式有:html

  • wait/notify 等待
  • Volatile 內存共享
  • CountDownLatch 併發工具
  • CyclicBarrier 併發工具

wait/notify

兩個線程交替打印奇偶數,經過wait/notify實現java

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 修飾內存可見性ide

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,下面重寫第一個例子:spa

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();
  }
}

結果:code

線程3: 準備...
線程2: 準備...
線程1: 準備...
所有啓動完畢!
所有啓動完畢!
所有啓動完畢!

參考資料

相關文章
相關標籤/搜索