Java 同期ブロックは、メソッドまたはコード ブロックを同期済みとしてマークするために使用されます。 Java 同期ブロックは競合を避けるために使用されます。この記事では次の内容を紹介します:
Java同期キーワード(同期)
インスタンスメソッドの同期
インスタンスメソッドの同期ブロック
静的メソッドの同期ブロック
Java 同期の例
Java 同期キーワード (synchronized)
するまでブロックされます。 4 つの異なる同期ブロックがあります:
インスタンス メソッド
静的メソッド
インスタンス メソッドの同期ブロック
静的メソッドの同期ブロック
上記の同期ブロックはすべて同期されていますさまざまなオブジェクトに。実際にどの同期ブロックが必要になるかは、状況によって異なります。
以下は、同期されたインスタンス メソッドです:
public synchronized void add(int value){ this.count += value; }
Java インスタンス メソッドの同期は、メソッドを所有するオブジェクトで同期されます。このようにして、各インスタンスのメソッドの同期は、異なるオブジェクト、つまりメソッドが属するインスタンス上で同期されます。インスタンス メソッド同期ブロック内で実行できるスレッドは 1 つだけです。複数のインスタンスが存在する場合、スレッドは一度に 1 つのインスタンス同期ブロックで操作を実行できます。インスタンスごとに 1 つのスレッド。
静的メソッドの同期
静的メソッドの同期は、インスタンス メソッドの同期メソッドと同じであり、synchronized キーワードも使用します。 Java の静的メソッドの同期は次のとおりです。
public static synchronized void add(int value){ count += value; }
静的メソッドの同期とは、メソッドが配置されているクラス オブジェクトでの同期を指します。クラスは Java 仮想マシン内の 1 つのクラス オブジェクトにのみ対応できるため、同じクラス内の静的同期メソッドを同時に実行できるスレッドは 1 つだけです。
異なるクラスの静的同期メソッドの場合、1 つのスレッドが各クラスの静的同期メソッドを待機せずに実行できます。クラス内のどの静的同期メソッドが呼び出されるかに関係なく、クラスは同時に 1 つのスレッドによってのみ実行できます。
インスタンス メソッド内の同期ブロック
場合によっては、メソッド全体を同期する必要はなく、メソッドの一部を同期する必要があります。 Java はメソッドの一部を同期できます。
public void add(int value){ synchronized(this){ this.count += value; } }
例では、Java 同期ブロック コンストラクターを使用して、コードのブロックを同期済みとしてマークします。このコードは同期メソッドのように実行されます。
Java 同期ブロック コンストラクターはオブジェクトをかっこで囲んでいることに注意してください。上記の例では、add メソッドを呼び出すインスタンス自体である「this」が使用されています。同期コンストラクタ内の括弧で囲まれたオブジェクトをモニタオブジェクトと呼びます。上記のコードはモニター オブジェクトの同期を使用しており、同期インスタンス メソッドは呼び出し元メソッド自体のインスタンスをモニター オブジェクトとして使用します。
同じモニター オブジェクトに同期された Java メソッド内で実行できるスレッドは一度に 1 つだけです。
次の 2 つの例はどちらも、呼び出されるインスタンス オブジェクトを同期するため、同期実行の効果は同等です。
public class MyClass { public synchronized void log1(String msg1, String msg2){ log.writeln(msg1); log.writeln(msg2); } public void log2(String msg1, String msg2){ synchronized(this){ log.writeln(msg1); log.writeln(msg2); } } }
上の例では、2 つの同期されたブロックのいずれかのメソッドで一度に 1 つのスレッドのみを実行できます。
2 番目の同期ブロックがこのインスタンス オブジェクトで同期されていない場合、スレッドによって 2 つのメソッドが同時に実行される可能性があります。
静的メソッドの同期ブロック
上記と同様に、静的メソッドの同期の例を 2 つ示します。これらのメソッドは、そのメソッドが属するクラス オブジェクト上で同期されます。
public class MyClass { public static synchronized void log1(String msg1, String msg2){ log.writeln(msg1); log.writeln(msg2); } public static void log2(String msg1, String msg2){ synchronized(MyClass.class){ log.writeln(msg1); log.writeln(msg2); } } }
2 番目の同期ブロックが MyClass.class オブジェクトで同期されていない場合。これにより、これら 2 つのメソッドにスレッドから同時にアクセスできるようになります。
Java 同期インスタンス
次の例では、2 つのスレッドが開始され、どちらも Counter クラスの同じインスタンスの add メソッドを呼び出します。同期はメソッドが属するインスタンス上で行われるため、メソッドに同時にアクセスできるスレッドは 1 つだけです。
public class Counter{ long count = 0; public synchronized void add(long value){ this.count += value; } } public class CounterThread extends Thread{ protected Counter counter = null; public CounterThread(Counter counter){ this.counter = counter; } public void run() { for(int i=0; i<10; i++){ counter.add(i); } } } public class Example { public static void main(String[] args){ Counter counter = new Counter(); Thread threadA = new CounterThread(counter); Thread threadB = new CounterThread(counter); threadA.start(); threadB.start(); } }
创建了两个线程。他们的构造器引用同一个Counter实例。Counter.add方法是同步在实例上,是因为add方法是实例方法并且被标记上synchronized关键字。因此每次只允许一个线程调用该方法。另外一个线程必须要等到第一个线程退出add()方法时,才能继续执行方法。
如果两个线程引用了两个不同的Counter实例,那么他们可以同时调用add()方法。这些方法调用了不同的对象,因此这些方法也就同步在不同的对象上。这些方法调用将不会被阻塞。如下面这个例子所示:
public class Example { public static void main(String[] args){ Counter counterA = new Counter(); Counter counterB = new Counter(); Thread threadA = new CounterThread(counterA); Thread threadB = new CounterThread(counterB); threadA.start(); threadB.start(); } }
注意这两个线程,threadA和threadB,不再引用同一个counter实例。CounterA和counterB的add方法同步在他们所属的对象上。调用counterA的add方法将不会阻塞调用counterB的add方法。
以上がJava 同期ブロックの使用方法の詳細な紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。