2011-01-17 22 views
1

次のクラスDoStuffはスレッドを開始し、nullのときにリスナーオブジェクトがアクセスされないように同期します。同期関数への外部呼び出しの保持/ロック

DoStuffクラスの関数setOnProgressListener()に外部からアクセスすると、関数呼び出しを終了する前に呼び出しが長時間保持されるため、問題が発生しています。なぜこのようなことが起こるのか分かりません。私は同期が多くのコールをキューに入れているかのように思えますか?これの入力は助けになります!

私はもはやこのステータスの更新を希望しないため、リスナーにnullを渡しています。私はDoStuff Threadを殺すプロセスの一環としてこれを行います。

ありがとうございます!

public class DoStuff extends Runnable 
{ 
    Object MUTEX = new Object(); 
    private OnProgressListener mOnProgressListener = null; 

    public DoStuff() 
    { 
     new Thread(this).start(); 
    } 

    public void setOnProgressListener(OnProgressListener onProgressListener) 
    { 
     synchronized (MUTEX) 
     { 
      mOnProgressListener = onProgressListener; 
     } 
    } 

    private void reportStatus(int statusId) 
    { 
     synchronized (MUTEX) 
     { 
      if (null != mOnStatusListener) 
      { 
       mOnStatusListener.setStatusMessage(new OnStatusEvent(this, statusId)); 
      } 
     } 
    } 

    // this is the run of a thread 
    public void run() 
    { 
     int status = 0; 
     do 
     { 
      // do some work and report the current work status 
      status = doWork(); 
      reportStatus(status); 
     } while(true); 
    } 
} 

答えて

0

ご協力いただきありがとうございます。なぜ私は不定のロックを決定することができた。何か重要かつ明白なことは、reportStatus()関数呼び出しを実行すると、コールバックの実行が完全に完了するまでロックMUTEXを保持するということです。私の欠点は、登録されたコールバックで誤ってsetOnProgressListener(null)を呼び出しているということでした。はい、私は十分なコードを投稿していないことを認め、おそらく皆さんがバグをキャッチしたでしょう... setOnProgressListener(null)を呼び出すと、MUTEXオブジェクトが解放され、reportStatus()がsetOnProgressListener(null)を呼び出すため、私はデッドロック状態に陥っていました。

私が学んだ主なポイントは、登録されたコールバック機能がコールの処理を完了するまで、コールバックメッセージのトリガーが保持されることです。

ありがとうございます!

1

このコードのトラブルは、あなたのwhile()ループが絶えず、すぐにそれを解放する、あるいはyield()スケジューラは別のスレッドを置く助けるために-ing後MUTEX用のモニタをつかむしようとしていることである。非常に良いチャンスがありますのでwhile()ループがCPU時間のほとんどを消費し、他のスレッドが実行できるときでも、待機中のモニターを取得できない可能性があるため、そのモニターを取得しようとしている他のユーザーは不足します。

理想的wait()/notify()ペアは、あなたが、少なくとも​​ブロックの外に、あなたのwhileループでThread.yield()を呼び出す必要があり、ことを使用したり、失敗しなければなりません。私はもう一度、コードを読んで、私はあなたが望んでいたものを見るために信じていると思う:(しかし、私この第二の「解決策」は本当にあなたが代わりに最初のものを使用することを検討する必要があり、非常に良いものではありません。)

UPDATE達成するために:新しい値を設定するたびにデータの値を出力する。それが本当であれば、確かにwait/notifyの解決策に進むべきですが、単一の値がすべて出力されることを絶対に保証したい場合は、キューを使用する必要があります。

+0

私は、簡略化した例では、重要ではないすべての点を見つけることができました。 :) – biziclop

0

あなたのコードについて少し混乱していますが、完全なリストを提供できますか?

まず、DoStuffはスレッドをどこから開始しますか?あなたのデータがまだヌルなら、なぜあなたは辞めますか? (実際にはsetDataが実行される前にスレッドから外れているかもしれません)。

ここで重要なことは、本質的にミューテックスを同期させるビジー待機ループを実行していることです。これはかなり無駄であり、一般にCPUのコアをブロックします。

何をしようとしているかに応じて、スレッドが何かが起きるまでスリープ状態になる待機通知スキームを使用することができます。

+0

私はもっと理にかなっていると思う質問を更新しました... – Jona

2

待機/通知を使用する必要があります。ここにサンプルです。

public class DoStuff { 
    Object MUTEX = new Object(); 
    String data = null; 

    public void setData(String data) { 
     synchronized (MUTEX) { 
      this.data = data; 
      System.out.println(Thread.currentThread()); 
      MUTEX.notifyAll(); 
     } 
    } 

    public void run() { 
     do { 
      synchronized (MUTEX) { 
       if (null == data) { 
        return; 
       } else { 
        System.out.println(data); 
       } 
       try { 
        MUTEX.wait(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     } while (true); 
    } 
} 
+0

正確には、単にInterruptedExceptionを飲み込むことは危険です。私はこれがプレゼンテーションのためだと知っていますが、OPはその事実を認識していなければなりません。 –

+0

ご意見ありがとうございます。実際の質問をより明確にするために質問を更新しました。私は十分な詳細を指定しなかったことを申し訳ありません。 – Jona

+0

私はそこにあなたのコードを参照してくださいが、実際にどのように私のコードが動作しない... run()関数でホールドはありません。それは自由自在に動作します。外部発信者は、物事を変更し、内部クラスを別の方法で動作させるものです。一番上の私の更新されたコードを見てください。 – Jona

関連する問題