synchronized をつけたメソッドは、スレッドがメソッドに入った場合、他のスレッドが入ってこないようにします。(ロックします。)
排他制御などと呼ばれます。
このロックはメソッドにかかるわけではなくインスタンス自体にかかります。
なので synchronized を付けたメソッドを持っているインスタンスは、他のメソッドも synchronized が付けられている場合が多いです。
synchronized はメソッドに付ける方法と synchronized 自体で部分を指定する方法があります。
・メソッドに付ける方法
synchronized void methodA(){
メソッドの処理
}
・ブロックで指定する方法
synchronized(ロックするインスタンスの変数名){
インスタンスに対する処理
}
・synchronized にスレッドが入ると、他のスレッドはどうなるのか。
他のスレッドはそのインスタンスの入り口で待機します。
そして synchronized に入っているスレッドが外に出たらロックが外れ、待機していた他のスレッドがそのインスタンスに入って来ます。複数のスレッドが待機していた場合、どのスレッドが入るかわかりませんが、待機していた一つのスレッドがインスタンスに入って、また synchronized をかけます。必ず一つのスレッドずつ処理されます。
・スレッドを待機、再開させる
wait メソッドでスレッドを待機させ notifyAll メソッドで待機中の全てのメソッドを再開させます。
synchronized method(){
while(待機させる条件){
wait();
}
notifyAll();
}
スレッドを待機再開させる場合、大体このように while 文を使ってきっちり動かす条件を指定させます。
1行目 synchronized を付けたメソッドにスレッドが入ってきます。
2行目 ループさせます。 notifyAll を通過しただけでは待機から抜けれないようにします。条件を満たして、他のスレッドが notifyAll を通過した場合に抜けるようにします。
3行目 wait でスレッドが待機します。この wait は便利な性質があり、ここに入ったスレッドは一旦見えなくなってしまいます。つまりメソッドにスレッドが入っていないことになり、インスタンス前で待機していた他のスレッドが入ることが出来ます。二番目に入ってきたスレッドが待機させる条件を満たしていた場合、同じように wait していきます。待機条件を抜けるスレッドが来た場合、 wait を通らず下に抜けます。
5行目 notifyAll をスレッドが通過すると、 wait していたスレッド達が全て動き始めます。しかし、 while があるので待機条件を抜けれないスレッドは再び wait に入って待機します。