2011-10-21 8 views
4

大きな質問があります。同じオブジェクトをロックするために同じクラスから2つの異なるメソッドを同期させるには?次に例を示します。Javaはオブジェクトに同期します

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を実行し、その逆されたときにはmyListをaccesingから?

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

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

L.E.

私はロックの概念を理解しましたが、もう別の質問があります。

public static myListのクラスがあり、そのクラスのインスタンスがの場合は、というインスタンスがあるとします。そのインスタンスから、Threadnインスタンスを作成し、そのリストのすべての要素を取得し、それを使っていくつかのことを行います。

ここで、特定の時点でmyListが更新されました。 myList要素をすでに処理していたスレッドではどうなりますか?アップデート中にmyListへのアクセスをロックするにはどうすればよいですか?

あなたが

両方の方法に

キーワードを同期を追加したり、前者は基本的にMyclass.classオブジェクトを使用していますが、それは微細なない

synchronized(Myclass.class) { 
} 

を使用することができますいずれか

+0

@Grammin私はそれは問題ではないと言います。 – Mob

+0

別の質問がある場合は、別の投稿を開くことをお勧めします。そうすればそれが見えます。 –

答えて

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 
     } 
    } 
    } 
} 

EDIT:追加外部エンティティは、リストを変更することができませんでしたように、リストのコピーを作成することJB Nizetあたりとして

EDIT 2:変数はプライベートメイドので、誰もが彼らに

にアクセスすることはできません
+3

しかし、欠陥があります:myListは外部から来るので、別のスレッドがロックをバイパスして直接myListにアクセスする保証はありません。コンストラクタは受け取ったリストの守備的なコピーを行うべきです。 –

+0

@JB Nizetそれを指摘してくれてありがとう - サンプルを修正しました。またインスタンスバールをプライベートにしました –

+0

"同期"の何が問題なのですか?これは、インスタンスをロックします。これは、オブジェクトが1つ少なくてもまったく同じように見えます。 – DJClayworth

1

両方の方法をすべてのインスタンスをロックするには​​と宣言するか、synchronized(this){...}ブロックを使用して現在のインスタンスのみをロックします。しかし、私はあなた自身を同期させることと、(たくさん)を取得するために避けるために達成したい何のためスレッドセーフな同時データ構造を使用することをお勧めIntrinsic Locks and Synchronization

4

次のことが可能です。

  1. は宣言の両方rundoJob​​。これはロックとしてthisを使用します。
  2. リストをfinalと宣言して同期します。これは、リストをロックとして使用します。ロックフィールドをfinalと宣言することは良い方法です。この方法でクラスのいくつかのメソッドがあるオブジェクトに同期しますが、他のメソッドは他のオブジェクトを使用して同期できます。これにより、ロックの競合は減少しますが、コードの複雑さは増します。
  3. 明示的なjava.util.concurrent.locks.Lock変数を導入し、同期の方法を使用します。これにより、コードの柔軟性は向上しますが、コードの複雑さも増します。
  4. 明示的な同期を一切行わず、代わりにJDKのスレッドセーフなデータ構造を使用します。たとえば、BlockingQueueまたはCopyOnWriteArrayListです。これにより、コードの複雑さが軽減され、スレッドの安全性が保証されます。
  5. volatileフィールドへの読み取り/書き込みによる同期を使用します。 SOの投稿thisを参照してください。これにより安全性は保証されますが、複雑性は大幅に増加します。 2番目の考えでは、これをしないでください:)
+1

Upvoted for(4.):並行リストを使用することで多くの問題を回避できます。 – toto2

+0

実行が実行されると同期され、ロックを解除しません。#1は動作しません。 #2には、他のオブジェクトがList上で動作し、それも同期させる必要があるという問題があります。 –

関連する問題