2017-05-13 3 views
1

私はJavaの初心者です。私はJavaの同時実行性を学びたいと考えています。私は生産者 - 消費者問題(単一の生産者と消費者)のための簡単なコードを書いています。データが利用可能なときに消費者に通知されないため、デッドロックが発生しているようです。コードを見直してもらえますか?あなたが実行されているためロックや条件を使用してこのプロデューサ - コンシューマのJavaでデッドロックが発生するのはなぜですか?

import java.util.List; 
import java.util.ArrayList; 
import java.util.concurrent.locks.*; 

class ThreadFactory implements Runnable{ 
    List<String> list = new ArrayList<>(); 
    Thread prThread; 
    final Lock lock = new ReentrantLock(); 
    final Condition notFull = lock.newCondition(); 
    final Condition notEmpty = lock.newCondition(); 
    final int CAPACITY = 10; 

    public enum Role{ 
    PRODUCER, 
    CONSUMER 
    }; 

    Role role; 
    public int i = 0; 

    private void produce() throws InterruptedException { 
     while(true){ 
      lock.lock(); 
      try{ 
       while(list.size() == CAPACITY){ 
        System.out.println("List is full to its CAPACITY, waiting"); 
        notEmpty.await(); 
       } 
       String str = "Data " + i++; 
       System.out.println("Putting " + str + " to list"); 
       list.add(str); 
       notFull.signalAll(); 
      } 
      finally{ 
       lock.unlock(); 
       Thread.sleep(500); 
      } 
     } 
    } 

    private void consume() throws InterruptedException{ 
     while(true){ 
      lock.lock(); 
      try{ 
       while(list.size() == 0){ 
        System.out.println("List is empty, waiting"); 
        notFull.await(); 
       } 
       String str = list.remove(list.size()-1); 
       System.out.println("Popping " + str + " from list"); 
       notEmpty.signal(); 
      } 
      finally{ 
       lock.unlock(); 
      } 
     } 
    } 

    public void run(){ 
     System.out.println("Starting thread " + prThread.getName()); 
     try{ 
      if(role == Role.PRODUCER){ 
       produce(); 
      }   
      else if(role == Role.CONSUMER){ 
       consume(); 
      } 
     } 
     catch(InterruptedException e){ 
      System.out.println("Thread interrupted"); 
     } 
    } 

    public ThreadFactory(List<String> l, int role, String name){ 
     this.list = l; 
     prThread = new Thread(this, name); 
     if(role == 0) 
      this.role = Role.PRODUCER; 
     else 
      this.role = Role.CONSUMER; 
     prThread.start(); 
    } 
} 

public class ProducerConsumer{ 
    public static void main(String[] args){ 
     List<String> l = new ArrayList<>(); 
     ThreadFactory c = new ThreadFactory(l,1, "Consumer"); 
     ThreadFactory p = new ThreadFactory(l,0, "Producer"); 
    } 
} 
+0

コンシューマまたはプロデューサのいずれかがロックを取得してその状態が発生するのを待つときに、ロックが解除されないようです。そのため、コードnotEmpty.await()を囲みます。 notFull.await(); lock.unlock()とlock.lock()によって呼び出されます。 – Shinchan

+0

提案に感謝します。この問題は@Nathanの言葉と同じでした。スレッドには独自のロックインスタンスがありました。私はロックと条件を静的にし、それは働いた。 –

答えて

1

これはデッドロックではありません。ロックは各クラスのインスタンスメンバーで、各実行可能インスタンスは独自のロックを作成します。あなたのプロデューサーと消費者は自分のロックを使用しているため、お互いの信号を見ず、永遠に待っています。同じロックを使用する必要があります。

+0

すごくありがとうございます。私はちょうどロックと条件変数を静的にし、すべてが機能しました。どうもありがとう :) –

-1

まあ、私は何が起こっているかのわからないんだけど、それかもしれは(()農産物を消費し、両方の)メソッドで方法実行()クラスのThreadFactory

私が行うことは、コンシューマ用のクラスとプロデューサ用のクラスを作成することです。どちらのクラスもクラスThreadを拡張します。次に、それぞれのクラスのrun()でconsume()とproducer()を呼び出します。

import java.util.ArrayList; 
import java.util.List; 
import java.util.concurrent.locks.Condition; 
import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 

class ThreadFactory { 
    List<String> list = new ArrayList<>(); 
    final Lock lock = new ReentrantLock(); 
    final Condition notFull = lock.newCondition(); 
    final Condition notEmpty = lock.newCondition(); 
    final int CAPACITY = 10; 

    public int i = 0; 

    class Producer extends Thread { 

     @Override 
     public void run() { 
      try { 
       produce(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    class Consumer extends Thread { 

     @Override 
     public void run() { 
      try { 
       consume(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    private void produce() throws InterruptedException { 
     System.out.println("Starting thread " + Thread.currentThread().getName()); 
     while (true) { 
      lock.lock(); 
      try { 
       while (list.size() == CAPACITY) { 
        System.out.println("List is full to its CAPACITY, producer waiting"); 
        notFull.await(); 
       } 
       if (i == CAPACITY) i=0; 
       String str = "Data " + i++; 
       System.out.println("Putting " + str + " to list of size "+list.size()); 
       list.add(str); 
       if (list.size() ==1) 
        notEmpty.signal(); 
      } finally { 
       lock.unlock(); 
       Thread.sleep(500); 
      } 
     } 
    } 

    private void consume() throws InterruptedException { 
     System.out.println("Starting thread " + Thread.currentThread().getName()); 
     while (true) { 
      lock.lock(); 
      try { 
       while (list.size() == 0) { 
        System.out.println("List is empty, consumer waiting"); 
        notEmpty.await(); 
       } 
       String str = list.remove(list.size() - 1); 
       System.out.println("Popping " + str + " from list of size "+list.size()); 
       if (list.size() ==CAPACITY-1) 
        notFull.signal(); 
      } finally { 
       lock.unlock(); 
      } 
     } 
    } 

    public ThreadFactory(List<String> l){ 
     this.list = l; 
     Thread p= new Producer(); 
     p.setName("Producer"); 
     p.start(); 
     Thread c=new Consumer(); 
     c.setName("Consumer"); 
     c.start(); 
    } 
} 

public class ProducerConsumer { 
    public static void main(String[] args) { 
     List<String> l = new ArrayList<>(); 
     ThreadFactory pc = new ThreadFactory(l); 
    } 
} 

これが役立ちます。

関連する問題