多線程與併發-線程間通信

多線程與併發-線程間通信

概述:
多線程之間通信一般有這樣幾種方法:

  • 通過共享對象實現通信
  • wait/notify機制
  • Condition接口,await/signal機制
  • 消息隊列,socket編程等網絡通信

wait/notify機制

基礎
前提:多個線程使用用一把鎖,在使用wait(),notify(),notifyAll()之前要先獲取當前對象的鎖。

  • wait():運行至wait處時立刻阻塞當前線程,並釋放鎖。當被通知喚醒後開始競爭鎖,如果獲取到鎖在繼續向下執行。
  • notify():運行至notify處時立刻發送通知喚醒一個等待線程,但需要等到同步塊運行結束之後才釋放鎖。
  • notifyAll():喚醒所有等待線程。
    其餘方法
  • wait(long millis),時間到了相當於被通知,自動喚醒

實現
生產者消費者爲例吧
單一緩存空間


public class A {
 private static String value;
 class MyService{
  private final String lock = new String("");
  private int i=0;
  public void produce(){
   synchronized (lock) {
    try {
     if(A.value!=null) {
      lock.wait();
     }
     A.value=" value = "+ i++;
     System.out.println("生產  :"+A.value);
     Thread.sleep(1000);
     lock.notify();
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
  }
  public void consume(){
   synchronized(lock) {
    try {
     if(A.value==null) {
      lock.wait();
     }
     System.out.println("消費  :"+A.value);
     A.value=null;
     Thread.sleep(1000);
     lock.notify();
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
  }
 }
 class ProduceThread extends Thread{
  private MyService service;
  ProduceThread(MyService service){
   this.service=service;
  }
  @Override
  public void run() {
   while(true) {
    service.produce();
   }
  }
 }
 class ConsumerThread extends Thread{
  private MyService service;
  ConsumerThread(MyService service){
   this.service=service;
  }
  @Override
  public void run() {
   while(true) {
    service.consume();
   }
  }
 }
 public static void main(String[] args) {
  A a = new A();
  MyService service = a.new MyService();
  a.new ProduceThread(service).start();
  a.new ConsumerThread(service).start();
  try {
   Thread.sleep(5000);
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  System.exit(0);
 }
}

緩存空間大於1


public class A {
 private static LinkedList<String> values = new LinkedList<>();
 private static final int SIZE = 5;
 class MyService{
  private final String lock = new String("");
  private int i=0;
  public void produce(){
   synchronized (lock) {
    try {
     while(A.values.size()==A.SIZE) {
      lock.wait();
     }
     String value =" value = "+ i++; 
     A.values.add(value);
     long id = Thread.currentThread().getId();
     System.out.printf("Thread %d 生產  :%s\n",id,value);
     lock.notifyAll();
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
   try {
    Thread.sleep(500);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
  public void consume(){
   synchronized(lock) {
    try {
     while(A.values.size()==0) {
      lock.wait();
     }
     String value = A.values.poll();
     long id = Thread.currentThread().getId();
     System.out.printf("Thread %d 消費   :%s\n",id,value);
     lock.notifyAll();
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
   try {
    Thread.sleep(500);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   
  }
 }
 class ProduceThread extends Thread{
  private MyService service;
  ProduceThread(MyService service){
   this.service=service;
  }
  @Override
  public void run() {
   while(true) {
    service.produce();
   }
  }
 }
 class ConsumerThread extends Thread{
  private MyService service;
  ConsumerThread(MyService service){
   this.service=service;
  }
  @Override
  public void run() {
   while(true) {
    service.consume();
   }
  }
 }
 public static void main(String[] args) {
  A a = new A();
  MyService service = a.new MyService();
  
  List<Thread> threads = new ArrayList<>(); 
  for(int i=0;i<10;i++) {
   threads.add(a.new ProduceThread(service));
   threads.add(a.new ConsumerThread(service));
   
  }
  for(Thread thread : threads) {
   thread.start();
  }
  try {
   Thread.sleep(10000);
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  System.exit(0);
 }
}

爲不讓單一線程完成所有生產或消費在外面休眠一定時間。
使用while與notifyAll避免假死現象出現(所有線程處於等待狀態),原因:notify只通知一個線程,可能是同類型線程而非異構線程(生產者->消費者,消費者->生產者)
同時也可以通過while避免等待條件發生改變,避免過早通知問題

Condition

await/signal機制
await()與wait()類似
signal()與notify類似,但通知的是同一個Condition

一個Lock對象可以創建多個Condition條件。實現部分通知功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章