5

同じオブジェクトをロックするために、同じクラスの 2 つの異なるメソッドを同期する方法は? 次に例を示します。

public class MyClass extends Thread implements Observer{
  public List<AnotherClass> myList = null;
  
  public MyClass(List<AnotherClass> myList){
    this.myList = myList;
  }
  
  public void run(){
    while(true){
       //Do some stuff 
       myList.add(NotImportantElement);
    }
  }

  public void doJob{
    for(int i=0; i<myList.size; i++){
      ElementClass x = myList.get(i);
      //Do some more stuff
    }
  }
}

問題は、doJob が実行されたときに run() が myList にアクセスしないようにするにはどうすればよいかということです。

これを想像してみてください: 私はスレッドを開始し、リストに要素を追加し始めます。ランダムな瞬間に、スレッドへの参照を保持する別のクラスから doJob() を呼び出します。

ロックはどうすればいいですか?ありがとう!

わかりました、ロックの概念は理解しましたが、別の質問があります。

クラスがあり、そのクラスのインスタンスが1 つpublic static myListだけあるとします。そのインスタンスから、そのリストのすべての要素を取得して何かを行うインスタンスを作成します。nThread

今、特定の瞬間にmyList更新されます。すでに myList 要素を処理していたスレッドはどうなりますか? myList更新中にアクセスをロックするにはどうすればよいですか?

4

5 に答える 5

5

あなたはできる:

  1. runとの両方を宣言しdoJob synchronizedます。これはthisロックとして使用されます。
  2. リストをとして宣言しfinal、同期します。これはリストをロックとして使用します。ロックフィールドを宣言するのfinalは良い習慣です。このようにして、クラスの一部のメソッドは1つのオブジェクトで同期しますが、他のメソッドは同期のために他のオブジェクトを使用できます。これにより、ロックの競合は減少しますが、コードの複雑さが増します。
  3. 明示的な変数を導入java.util.concurrent.locks.Lockし、そのメソッドを同期に使用します。これにより、コードの柔軟性が向上しますが、コードの複雑さも増します。
  4. 明示的な同期を完全に行わず、代わりにJDKのスレッドセーフなデータ構造を使用してください。たとえば、BlockingQueueまたはCopyOnWriteArrayList。これにより、コードの複雑さが軽減され、スレッドセーフが確保されます。
  5. フィールドへの読み取り/書き込みによる同期を採用しvolatileます。このSOの投稿を参照してください。これにより安全性が確保されますが、複雑さが大幅に増します。考え直して、これをしないでください:)
于 2011-10-21T15:31:32.107 に答える
5

注: このコードは、MyClass のインスタンスが 1 つしかないことを前提としています。あなたの投稿によると、そのように聞こえます。

public class MyClass extends Thread implements Observer{
  private List<AnotherClass> myList = null;
  private Object lock = new Object();

  public MyClass(List<AnotherClass> myList){
    this.myList = new ArrayList(myList);
  }

  public void run(){
    while(true){
       //Do some stuff 
       synchronized(lock) {
        myList.add(NotImportantElement);
       }
    }
  }

  public void doJob{
    synchronized(lock) {
      for(int i=0; i<myList.size; i++){
        ElementClass x = myList.get(i);
        //Do some more stuff
      }
    }
  }
}

編集:外部エンティティが JB Nizet に従ってリストを変更できないように、リストのコピーを作成することを追加しました

編集 2:変数を非公開にして、他の誰もアクセスできないようにしました

于 2011-10-21T15:28:01.913 に答える
1
synchronized(myList) {
    // do stuff on myList
}

特定のドキュメント:固有のロックと同期

それでも、達成したいことのためにスレッドセーフな並行データ構造を使用して、自分自身の同期を回避し、(はるかに) 優れたパフォーマンスを得ることをお勧めします:並行パッケージの概要

于 2011-10-21T15:27:44.793 に答える
1

追加することができます

同期

キーワードを両方のメソッドに追加するか、

synchronized(Myclass.class) {
}

前者は基本的に Myclass.class オブジェクトを使用しますが、後者ほどきめの細かいものではありません。

于 2011-10-21T15:24:41.670 に答える
1

synchronizedすべてのインスタンスをロックするように両方のメソッドを宣言するか、synchronized(this){...}ブロックを使用して現在のインスタンスのみをロックします。

于 2011-10-21T15:25:05.330 に答える