線程間的通信——生產者消費者問題

線程間的通信——生產者消費者問題

【題目一】

  • 用兩個線程操作初始值爲0的資源類,一個線程進行加操作,另一個線程進行減操作:

【思路】

  1. 線程、操作、資源類
  2. 判斷、幹活、通知(synchronized)

【代碼】

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class ShareDataOne//資源類
{
  private int number = 0;//初始值爲零的一個變量
  public synchronized void increment() throws InterruptedException 
  {
     //1判斷
     if(number !=0 ) {
       this.wait();
     }
     //2幹活
     ++number;
     System.out.println(Thread.currentThread().getName()+"\t"+number);
     //3通知
     this.notifyAll();
  }

  public synchronized void decrement() throws InterruptedException 
  {
     // 1判斷
     if (number == 0) {
       this.wait();
     }
     // 2幹活
     --number;
     System.out.println(Thread.currentThread().getName() + "\t" + number);
     // 3通知
     this.notifyAll();
  }
}

public class NotifyWaitDemoOne
{
  public static void main(String[] args)
  {
     ShareDataOne sd = new ShareDataOne();
     new Thread(() -> {//線程一
       for (int i = 1; i < 10; i++) {
          try {
            sd.increment();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
       }
     }, "A").start();
     new Thread(() -> {//線程二
       for (int i = 1; i < 10; i++) {
          try {
            sd.decrement();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
       }
     }, "B").start();
  }
}

【題目二】

  • 在【題目一】的基礎上改爲多個線程進行加操作,多個線程進行減操作:

【思路】

  • 繼續使用if語句判斷會造成spurious weakup(虛假喚醒),使用while循環可以將等待的線程重新進行判斷

【代碼】

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.omg.IOP.Codec;

class ShareData//資源類
{
  private int number = 0;//初始值爲零的一個變量

  public synchronized void increment() throws InterruptedException 
  {
     //判斷
     while(number!=0) {
       this.wait();
     }
     //幹活
     ++number;
     System.out.println(Thread.currentThread().getName()+" \t "+number);
     //通知
     this.notifyAll();;
  }
  
  public synchronized void decrement() throws InterruptedException 
  {
     //判斷
     while(number!=1) {
       this.wait();
     }
     //幹活
     --number;
     System.out.println(Thread.currentThread().getName()+" \t "+number);
     //通知
     this.notifyAll();
  }
}

public class NotifyWaitDemo
{
  public static void main(String[] args)
  {
     ShareData sd = new ShareData();
      //四個線程
     new Thread(() -> {
       for (int i = 1; i <= 10; i++) {
          try {
            sd.increment();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
       }
     }, "A").start();
     new Thread(() -> {
       for (int i = 1; i <= 10; i++) {
          try {
            sd.decrement();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
       }
     }, "B").start();
     new Thread(() -> {
       for (int i = 1; i <= 10; i++) {
          try {
            sd.increment();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
       }
     }, "C").start();
     new Thread(() -> {
       for (int i = 1; i <= 10; i++) {
          try {
            sd.decrement();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
       }
     }, "D").start();
  }
}

【題目三】

  • 使用synchronized時用wait()和notify()/notifyAll()(Object類中)操作線程,現在改成使用Condition的await()和signal()/signalAll()(Condition類中)操作線程:

【思路】

  • 將synchronized去掉,並將wait()和notify()/notifyAll()改寫成lock的await()和signal()/signalAll()

【代碼】

import org.omg.IOP.Codec;
class ShareData//資源類
{
  private int number = 0;//初始值爲零的一個變量
  private Lock lock = new ReentrantLock();
  private Condition condition  = lock.newCondition(); 
  public  void increment() throws InterruptedException 
  {
      lock.lock();
         try {
          //判斷
          while(number!=0) {
            condition.await();
          }
          //幹活
          ++number;
          System.out.println(Thread.currentThread().getName()+" \t "+number);
          //通知
          condition.signalAll();
     } catch (Exception e) {
       e.printStackTrace();
     } finally {
       lock.unlock();
     }
  }
  public  void decrement() throws InterruptedException 
  {   
      lock.lock();
         try {
          //判斷
          while(number!=1) {
            condition.await();
          }
          //幹活
          --number;
          System.out.println(Thread.currentThread().getName()+" \t "+number);
          //通知
          condition.signalAll();
     } catch (Exception e) {
       e.printStackTrace();
     } finally {
       lock.unlock();
     }
  }
  /*public synchronized void increment() throws InterruptedException 
  {
     //判斷
     while(number!=0) {
       this.wait();
     }
     //幹活
     ++number;
     System.out.println(Thread.currentThread().getName()+" \t "+number);
     //通知
     this.notifyAll();;
  }
  public synchronized void decrement() throws InterruptedException 
  {
     //判斷
     while(number!=1) {
       this.wait();
     }
     //幹活
     --number;
     System.out.println(Thread.currentThread().getName()+" \t "+number);
     //通知
     this.notifyAll();
  }*/
}

public class NotifyWaitDemo
{
  public static void main(String[] args)
  {
     ShareData sd = new ShareData();
     new Thread(() -> {
       for (int i = 1; i <= 10; i++) {
          try {
            sd.increment();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
       }
     }, "A").start();
     new Thread(() -> {
       for (int i = 1; i <= 10; i++) {
          try {
            sd.decrement();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
       }
     }, "B").start();
     new Thread(() -> {
       for (int i = 1; i <= 10; i++) {
          try {
            sd.increment();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
       }
     }, "C").start();
     new Thread(() -> {
       for (int i = 1; i <= 10; i++) {
          try {
            sd.decrement();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
       }
     }, "D").start();
  }
}

【題目四】

  • 多線程之間按順序調用,實現A->B->C,三個線程啓動,要求如下:AA打印5次,BB打印10次,CC打印15次,接着AA打印5次,BB打印10次,CC打印15次…輪流10次。

【思路】

  • 原來的synchronized無法實現多線程之間按順序調用,通過使用Condition的標誌位(配多把鎖,即多個condition對象)可以完成特定鎖的喚醒

【代碼】

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class ShareResource
{
  private int number = 1;//1:A 2:B 3:C 
  private Lock lock = new ReentrantLock();
  private Condition c1 = lock.newCondition();
  private Condition c2 = lock.newCondition();
  private Condition c3 = lock.newCondition();
  public void print5(int totalLoopNumber)
  {
     lock.lock();
     try 
     {
       //1 判斷
       while(number != 1)
       {
          //A 就要停止
          c1.await();
       }
       //2 幹活
       for (int i = 1; i <=5; i++) 
       {
          System.out.println(Thread.currentThread().getName()+"\t"+i+"\t totalLoopNumber: "+totalLoopNumber);
       }
       //3 通知
       number = 2;
       c2.signal();
     } catch (Exception e) {
       e.printStackTrace();
     } finally {
       lock.unlock();
     }
  }
  public void print10(int totalLoopNumber)
  {
     lock.lock();
     try 
     {
       //1 判斷
       while(number != 2)
       {
          //A 就要停止
          c2.await();
       }
       //2 幹活
       for (int i = 1; i <=10; i++) 
       {
          System.out.println(Thread.currentThread().getName()+"\t"+i+"\t totalLoopNumber: "+totalLoopNumber);
       }
       //3 通知
       number = 3;
       c3.signal();
     } catch (Exception e) {
       e.printStackTrace();
     } finally {
       lock.unlock();
     }
  }  
  public void print15(int totalLoopNumber)
  {
     lock.lock();
     try 
     {
       //1 判斷
       while(number != 3)
       {
          //A 就要停止
          c3.await();
       }
       //2 幹活
       for (int i = 1; i <=15; i++) 
       {
          System.out.println(Thread.currentThread().getName()+"\t"+i+"\t totalLoopNumber: "+totalLoopNumber);
       }
       //3 通知
       number = 1;
       c1.signal();
     } catch (Exception e) {
       e.printStackTrace();
     } finally {
       lock.unlock();
     }
  }  
}

public class ThreadOrderAccess
{
  public static void main(String[] args)
  {
     ShareResource sr = new ShareResource();
     new Thread(() -> {
       for (int i = 1; i <=10; i++) 
       {
          sr.print5(i);
       }
     }, "AA").start();
     new Thread(() -> {
       for (int i = 1; i <=10; i++) 
       {
          sr.print10(i);
       }
     }, "BB").start();
     new Thread(() -> {
       for (int i = 1; i <=10; i++) 
       {
          sr.print15(i);
       }
     }, "CC").start();   
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章