この小さくシンプルなサンプルを使用してみましょう。
class Sample {
private String msg = null;
public void newmsg(String x){
msg = x;
}
public String getmsg(){
String temp = msg;
msg = null;
return temp;
}
}
関数newmsg()
が、アクセスできない他のスレッドによって呼び出されると仮定しましょう。
Synchonizeメソッドを使用して、文字列msg
が一度に1つの関数でのみ使用されるようにします。つまり、関数newmsg()
はgetmsg()
と同時に実行できません。
それはとても簡単です:
class Sample {
private String message = null;
private final Object lock = new Object();
public void newMessage(String x) {
synchronized (lock) {
message = x;
}
}
public String getMessage() {
synchronized (lock) {
String temp = message;
message = null;
return temp;
}
}
}
I did n'tメソッド自体を同期させるか、this
で同期させることに注意してください。 意図的にロックを公開していない限り、コードのみがアクセスできるオブジェクトのロックのみを取得することをお勧めします。これにより、コードなどとは異なる順序でロックを取得するものが他にないことを安心させることがはるかに容易になります。
この機能を使用するには、ロックをまったく使用しないほうが良いでしょう。 AtomicReferenceを試してください。
public class Sample {
private final AtomicReference<String> msg = new AtomicReference<String>();
public void setMsg(String x) {
msg.set(x);
}
public String getMsg() {
return msg.getAndSet(null);
}
}
ロックは不要で、コードはシンプルです。いずれにせよ、それはあなたが望むことをする標準的な構造を使用します。
Java 1.5以降、Java.util.concurrentパッケージを検討することは常に良い考えです。現在、Javaの最先端のロックメカニズムです。同期メカニズムは、Java.util.concurrentクラスよりも重いです。
例は次のようになります。
import Java.util.concurrent.locks.Lock;
import Java.util.concurrent.locks.ReentrantLock;
public class Sample {
private final Lock lock = new ReentrantLock();
private String message = null;
public void newmsg(String msg) {
lock.lock();
try {
message = msg;
} finally {
lock.unlock();
}
}
public String getmsg() {
lock.lock();
try {
String temp = message;
message = null;
return temp;
} finally {
lock.unlock();
}
}
}
この簡単な例では、両方のメソッドシグネチャでsynchronized
の後に修飾子としてpublic
を置くことができます。
より複雑なシナリオには、他のものが必要です。
synchronized
キーワードを使用します。
class sample {
private String msg=null;
public synchronized void newmsg(String x){
msg=x;
}
public synchronized string getmsg(){
String temp=msg;
msg=null;
return msg;
}
}
メソッドでsynchronized
キーワードを使用するには、sample
のインスタンスのロックを取得するスレッドが必要です。したがって、いずれかのスレッドがnewmsg()
にある場合、getmsg()
を呼び出そうとしても、他のスレッドはsample
のインスタンスをロックできません。
一方、メソッドが長時間実行される場合、synchronized
メソッドの使用がボトルネックになる可能性があります。すべてのスレッドは、インターリーブ可能なオブジェクト内の他のメソッドを呼び出したい場合でも、待機する必要があります。
IMOの簡単な例では、実際にはインターリーブされるべきではない2つのメソッドがあるため、同期メソッドを使用しても問題ありません。ただし、異なる状況では、Joh Skeetの回答に示されているように、同期するロックオブジェクトがある方が理にかなっている場合があります。
別の機会に文字列ではなくコレクションを同期している場合、おそらくコレクションを繰り返し処理していて、それが変化するのではないかと心配している場合、Java 5は以下を提供します。