2015-10-27 11 views
5

私は両方ともベクトルにアクセスする2つのスレッドを持っています。 t1は乱数を追加し、t2は最初の数を削除して出力します。以下はコードと出力です。 t2は1回だけ(t1が始まる前に)実行され、永遠に終了します。私はここに何かを逃していますか(PS:同様のArrayListでテスト済み)2つのスレッドを持つベクトル(またはArrayList)への書き込み/読み込み

import java.util.Random; 
import java.util.Vector; 

public class Main { 

public static Vector<Integer> list1 = new Vector<Integer>(); 

public static void main(String[] args) throws InterruptedException { 
    System.out.println("Main started!"); 

    Thread t1 = new Thread(new Runnable() { 

     @Override 
     public void run() { 
      System.out.println("writer started! "); 
      Random rand = new Random(); 

      for(int i=0; i<10; i++) { 
       int x = rand.nextInt(100); 
       list1.add(x); 
       System.out.println("writer: " + x); 
       try { 
        Thread.sleep(1000); 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      }    
     } 

    }); 

    Thread t2 = new Thread(new Runnable() { 

     @Override 
     public void run() { 
      System.out.println("reader started! ");   
      while(!list1.isEmpty()) { 

       int x = list1.remove(0); 
       System.out.println("reader: "+x); 
       try { 
        Thread.sleep(1000); 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      }    
     } 

    }); 


    t2.start(); 
    t1.start(); 

    t1.join(); 
    t2.join();  
} 

} 出力: メインが開始! リーダーが開始!作家開始! ! ライタ:40 ライタ:9 ライター:23 ライター:5 ライター:41 ライター:29 ライター:72 ライター:73 ライター:95 ライター:46

+1

はい、 't2'が始まるとリストに何もないので、' while'は終了する前に終了します。 – RealSkeptic

+1

また、 'ArrayList'はスレッドセーフではないので、壊れた例で、外部同期はありません。 – Kayaman

+0

@RealSkeptic:t2を機能させる方法はありますか? –

答えて

4

これは並行性を理解するためのおもちゃのように聞こえるので、私はこれまで言及していませんでしたが、重要なので上部に表示されます。

これが生産コードである場合は、自分のロールをかけないでください。 java.util.concurrentには、よく実装された(デバッグされた)並行データ構造がたくさんあります。それらを使用してください。


消費するときは、消費されたすべてのアイテムに基づいて消費者をシャットダウンする必要はありません。これは、消費者がプロデューサーの「先走り」し、プロデューサーが消費アイテムをまだ書いていないために空のリストしか検出できない競争状態に起因します。

コンシューマのシャットダウンを実行するにはいくつかの方法がありますが、単独で消費するデータを調べることはできません。

私の推薦は、生産者が生産を完了したときに、消費者が消費者に「シグナルを送る」ことです。消費者は、「信号」が生成されなくなり、リストが空になると停止します。

「シャットダウン」項目を作成する方法があります。 「プロデューサ」はシャットダウン項目を追加し、「シャットダウン」項目が表示されたときにのみ終了します。コンシューマのグループがある場合は、シャットダウン項目を削除しないでください(ある消費者だけがシャットダウンします)。

また、消費者はプロデューサを「監視」することができ、プロデューサが「生存/存在」であり、リストが空の場合、消費者はより多くのデータが利用可能になると想定する。シャットダウンは、プロデューサが死んでいるか存在しておらず、データがないときに発生します。

どの手法を使用するかは、お好みの方法と解決しようとしている問題によって異なります。


私は、エレガントなソリューションが好きだと知っていますが、単一のプロデューサーが単一のコンシューマーを認識している場合は、最初のオプションがあります。消費者は、リスト上のアイテムを周りにロックするように不足が本質的に危険ですが、あなたは、単一の消費者を述べたので、何の競合からの読み取りのためにそこにいないことを{

public class Consumer { 

    private boolean shuttingDown = false; 

    public void shutdown() { 
    shuttingDown = true; 
    } 

    public void run() { 
    if (!list.isEmpty() && !shuttingDown) { 
     // pull item and process 
    } 
    } 
} 

ノートのように見えます

public class Producer { 

    public void shutdown() { 
     addRemainingItems(); 
     consumer.shutdown(); 
    } 
} 

リスト。

複数のコンシューマがある場合は、1つのアイテムが2つのスレッドで同時にプルされないように保護する必要があります(すべてのスレッドがシャットダウンするように通信する必要があります)。

+0

詳細な説明をありがとう。私はセマフォーでテストを開始し、それがうまく動作しない場合はモニターを試します。 –

+0

セマフォはこれを行う方法の1つですが、より簡単な方法があります。 –

+0

エドウィン、あなたは大丈夫です!これはプロダクションコードではありません。あなたの素晴らしいご意見ありがとうございます。 –

0

私は、これが一般的だと思いますProducer–consumer problem。詳細はSemaphoreをご覧ください。

+0

これは生産者/消費者の問題(オーバーラン/アンダーラン)以上のものです。問題は、消費を待つか、終了するかを決める方法です。 – RealSkeptic

+0

私はセマフォを試します。 –

0

更新:消費者(リーダー)のwhileループを変更した後に問題が発生しました。リストが空の場合にスレッドを終了する代わりに、ループに入りますが、何もしません。以下は更新されたリーダースレッドです。もちろん、まともなシャットダウンの仕組みをEdwinのようなコードに追加することもできます。

 public void run() { 
     System.out.println("reader started! ");   
     while(true) { 
      if(!list1.isEmpty()) { 
       int x = list1.remove(0); 
       System.out.println("reader: "+x); 
       try { 
        Thread.sleep(100); 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      } 
     }    
    } 

実際の製品から取得したコードスニペットではありません。

関連する問題