2012-03-12 10 views
0

私は同期ブロックを理解するための助けが必要です。以下の例を仮定:Javaスレッド:synchronizedブロック

public class ThreadStarter { 
    public static void main(String[] args) { 

     Queue queueObject = new Queue(); 

     ThreadA thread1 = new ThreadA(queueObject); 
     ThreadA thread2 = new ThreadA(queueObject); 

     ThreadB thread3 = new ThreadB(queueObject); 
     ThreadB thread4 = new ThreadB(queueObject); 

     thread1.start(); 
     thread2.start(); 

    } 
} 

public class Queue { 

    Object[] the theQueue; 

    public Queue(int size){ 
     theQueue = new Object[size]; 
    } 

    public submitObject(Object o){ 
     /* add Object to the queue */ 
    } 

    public deleteObject(int objectId){ 
     /*delete Object from the queue */ 
    } 
} 

public class ThreadA extends Thread { 

    private Queue queue; 

    public ThreadA(Queue queue){ 
     this.queue = queue; 
    } 

    public void run() { 
     while(!isInterrupted()){ 
      synchronized(queue) { 
       Object o = new Object 
       queue.submitObject(o); 
       /* do some other stuff */ 
     } 

     try { 
      sleep((int)(Math.random()*1000)); 
     } catch (interruptedException) { 
      Thread.currentThread().interrupt; 
     } 

      synchronized(queue) { 
       /* do some other stuff on the queue */ 
      } 
     } 
    } 
} 

public class ThreadB extends Thread { 

    private Queue queue; 

    public ThreadB(Queue queue){ 
     this.queue = queue; 
    } 

    public void run() { 
     while(!isInterrupted()){ 
      synchronized(queue) { 
       queue.deleteObject(o); 
       /* do some other stuff */ 
     } 

     try { 
      sleep(1000); 
     } catch (interruptedException) { 
      Thread.currentThread().interrupt; 
     } 
    } 
} 
} 

私の質問があり、それは十分に安全側であることを、キュークラスにオブジェクトを提出するスレッドAで全体キューオブジェクトを同期させることですか? ThreadBで同じことをして、キューからオブジェクトを削除しました。または、QueueクラスのsubmitObject()メソッドとdeleteObject()メソッドを同期させる必要がありますか?

私の理解では、上記のようにスレッドのクラス全体をロックすると、私は安全な側にいるはずです。

greetZと事前に感謝します。

答えて

2

あなたがここで行う必要があるのは、2つのスレッドがsubmitObject & deleteObjecct内に同時に入ることができないことを確認することだけです。これを実現するには、これらのメソッドを同期させて宣言してください。 その場合、クラス間で共有されるキューオブジェクトは、2つのスレッドが同期しているブロック上に存在しないようにします。

したい場合は、さらに、のようなメカニズムをブロックのいくつかの種類を持っている:

「のスレッドがオブジェクトを削除したい場合は、それが中にそのようなオブジェクト が存在しない場合は待機しなければなりませんキュー。"

、あなたはちょうどそのように同期する以上のことをする必要があります。両方の方法は、まだ同期させる必要がありますが、オブジェクトが利用可能になるまでDeleteObjectの中に入るスレッドは、キューによってthis.wait使用して停止する必要があります。

public synchronized deleteObject() { 
    while(isEmpty()) { 
    try { 
     wait(); 
    } catch(Exception ex) { 
     ex.printStackTrace(); 
    }//catch 
    }//while 

    //actually do delete object. 
    ... 
}//met 

と その後、実行して待機状態にあるスレッドに通知しなければならないsubmitObject:あなたも役割を渡り、中のために両方の方法でいくつかのコードを追加することができますし、

public synchronized submitObject() { 
    //do put object 
    ... 
    notifyAll(); 
}//met 

をスタンスは、キューがいっぱいになるとサブミッターをブロックし、キューにスペースが残っているときに通知することを許可します。

1

私はsubmitObjectdeleteObject方法でキューのオブジェクトで同期う、これは十分なはず、ということを意味:あなたは何

public submitObject(Object o){ 
    synchronized (theQueue) { 
     ... 
    } 
} 

public deleteObject(int objectId){ 
    synchronized (theQueue) { 
     ... 
    } 
} 
1

は(public synchronized method()があなたのqueueあるthisと同期しているメソッドを同期と同等ですローカル変数)。ただし、キューを使用するたびに実行する必要があることを覚えておく必要があります。送信と削除の方法を同期する方が安全です。 同期ブロックからObject o = new Object()も削除されます。

+0

+1:同期をカプセル化するほど、より簡単で安全です。 –

+1

機能的には、 'queue'のメソッドを同期させることと同等ではありません。彼がそれをした場合、各 'synchronized 'セクションにある'/* do some other stuff */'はクリティカルセクションにはなく、並行して実行できます。そのコードの内容によっては、同期することも重要です。これは同期されたリストに似ています。複数の操作をアトミックに(たとえば反復処理を)実行する場合は、リスト上で外部的に同期する必要があります。 –

+0

@MaxPeters完全に同意します。 – assylias

関連する問題