歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Java多線程(同步與死鎖問題,生產者與消費者問題)

首先我們來看同步與死鎖問題:

所謂死鎖,就是A擁有banana,B擁有apple。

A對B說:你把apple給我,我就把banana給你。

B對A說:你把banana給我,我就把apple給你。

但是A和B都在等待對方的答復,那麼這樣最終的結果就是A得不到apple,B也得不到banana。這種死循環就是死鎖。

於是我們可以模擬上面的描述,寫出以下代碼:

類A代表A這個人,

public class A {
 public void say(){
  System.out.println("A said to B: if you give me the apple, I will give you the banana.");
 }
 public void get(){
  System.out.println("A get the apple.");
 }
}

類B代表B這個人,

public class B {
 public void say(){
  System.out.println("B said to A: if you give me the banana, I will give you the apple.");
 }
 public void get(){
  System.out.println("B get the banana.");
 }
}

類ThreadDeadLock代表死鎖類,

public class ThreadDeadLock implements Runnable{
 private static A a=new A();
 private static B b=new B();
 public boolean flag=false;
 public void run(){
  if(flag){
   synchronized(a){
    a.say();
    try{
     Thread.sleep(500);
    }catch(InterruptedException e){
     e.printStackTrace();
    }
    synchronized(b){
     a.get();
    }
   }
  }else{
   synchronized(b){
    b.say();
    try{
     Thread.sleep(500);
    }catch(InterruptedException e){
     e.printStackTrace();
    }
    synchronized(a){
     b.get();
    }
   }
  }
 }
}

下面是主類:

public class Main{
 public static void main(String[] args){
  ThreadDeadLock t1=new ThreadDeadLock();
  ThreadDeadLock t2=new ThreadDeadLock();
  t1.flag=true;
  t2.flag=false;
  Thread thA=new Thread(t1);
  Thread thB=new Thread(t2);
  thA.start();
  thB.start();
 }
}

程序運行結果:
A said to B: if you give me the apple, I will give you the banana.
B said to A: if you give me the banana, I will give you the apple.

從以上的程序運行,我們可以發現,兩個線程都在等待對方的執行完成,這樣,程序也就無法繼續執行,從而造成了死鎖運行現象。

下面我們來看生產者與消費者問題:

所謂生產者與消費者問題,很簡單,過程就是生產者不斷生產產品,消費者不斷取走產品。

Producer生產product,Consumer消費product。

於是,我們先定義product類:

public class Product {
 private String name="product";
 private boolean flag=false;
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public synchronized void set(String name){
  if(!flag){
   try{
    super.wait();
   }catch(InterruptedException e){
    e.printStackTrace();
   }
  }
  this.setName(name);
  try{
   Thread.sleep(300);
  }catch(InterruptedException e){
   e.printStackTrace();
  }
  flag=false;
  super.notify();
 }
 public synchronized void get(){
  if(flag){
   try{
    super.wait();
   }catch(InterruptedException e){
    e.printStackTrace();
   }
  }
  try{
   Thread.sleep(300);
  }catch(InterruptedException e){
   e.printStackTrace();
  }
  System.out.println(this.getName());
  flag=true;
  super.notify();
 }
}

這裡加入了等待與喚醒,並增加一個標志位flag,flag為true時,表示可以生產,但不能取走,此時如果線程執行到了消費者線程,則應該等待,如果flag為false,則表示可以取走,但是不能生產,如果生產者線程運行,則應該等待。

Producer類:

public class Producer implements Runnable{
 private Product product=null;
 public Producer(Product product){
  this.product=product;
 }
 public void run(){
  for(int i=0;i<50;++i){
   this.product.set("product");
  }
 }
}

Consumer類:

public class Consumer implements Runnable{
 private Product product=null;
 public Consumer(Product product){
  this.product=product;
 }
 public void run(){
  for(int i=0;i<50;++i){
   try{
    Thread.sleep(100);
   }catch(InterruptedException e){
    e.printStackTrace();
   }
   this.product.get();
  }
 }
}

然後是主類:

public class Main{
 public static void main(String[] args){
  Product product=new Product();
  Producer pro=new Producer(product);
  Consumer con=new Consumer(product);
  new Thread(pro).start();
  new Thread(con).start();
 }
}

於是我們知道,生產者每生產一個產品,消費者就取走一個產品,消費者每取走一個產品,就要等待生產者生產。

Copyright © Linux教程網 All Rights Reserved