Java での同期

マルチスレッド プログラムでは、複数のスレッドが同じリソースにアクセスしようとし、最終的には誤った予期しない結果が生成されるという状況に陥ることがよくあります。

Java 同期を使用する理由

Java 同期は、何らかの同期メソッドによって、特定の時点で 1 つのスレッドだけがリソースにアクセスできるようにするために使用されます。

Java同期ブロック

Java は、同期ブロックを使用してスレッドを作成し、そのタスクを同期する方法を提供します。

Java の同期ブロックは、あるオブジェクトに対して同期されます。すべての同期ブロックは同じオブジェクト上で同期し、ブロック内で一度に実行できるスレッドは 1 つだけです。同期ブロックに入ろうとする他のすべてのスレッドは、同期ブロック内のスレッドがブロックから出るまでブロックされます。

注記: Java の同期ブロックは、synchronized キーワードでマークされます。

同期ブロックの一般的な形式

// Only one thread can execute at a time. // sync_object is a reference to an object // whose lock associates with the monitor . // The code is said to be synchronized on // the monitor object synchronized(sync_object) { // Access shared variables and other // shared resources } 

この同期は、モニターまたはロックと呼ばれる概念を使用して Java に実装されます。特定の時点でモニターを所有できるのは 1 つのスレッドだけです。スレッドがロックを取得すると、そのスレッドはモニターに入ったと言われます。ロックされたモニターに入ろうとする他のすべてのスレッドは、最初のスレッドがモニターから出るまで一時停止されます。

同期の種類

Java には以下の 2 つの同期があります。

  1. プロセスの同期
  2. スレッドの同期

1. Java でのプロセスの同期

プロセス同期は、複数のプロセスの実行を調整するために使用される技術です。これにより、共有リソースが安全かつ正常に保たれることが保証されます。

2. Java でのスレッド同期

スレッド同期は、マルチスレッド プログラム内のスレッドの実行を調整し、順序付けするために使用されます。スレッド同期には次の 2 種類があります。

  • 相互排他的
  • 連携(Javaにおけるスレッド間通信)

相互排他的

相互排他的機能は、データ共有中にスレッドが相互に干渉するのを防ぐのに役立ちます。相互排他には、以下の 3 つのタイプがあります。

  • 同期メソッド。
  • 同期ブロック。
  • 静的同期。

同期の例

以下は Java 同期の実装です。

ジャワ




// A Java program to demonstrate working of> // synchronized.> import> java.io.*;> import> java.util.*;> // A Class used to send a message> class> Sender {> > public> void> send(String msg)> > {> > System.out.println(> 'Sending '> + msg);> > try> {> > Thread.sleep(> 1000> );> > }> > catch> (Exception e) {> > System.out.println(> 'Thread interrupted.'> );> > }> > System.out.println(> ' '> + msg +> 'Sent'> );> > }> }> // Class for send a message using Threads> class> ThreadedSend> extends> Thread {> > private> String msg;> > Sender sender;> > // Receives a message object and a string> > // message to be sent> > ThreadedSend(String m, Sender obj)> > {> > msg = m;> > sender = obj;> > }> > public> void> run()> > {> > // Only one thread can send a message> > // at a time.> > synchronized> (sender)> > {> > // synchronizing the send object> > sender.send(msg);> > }> > }> }> // Driver class> class> SyncDemo {> > public> static> void> main(String args[])> > {> > Sender send => new> Sender();> > ThreadedSend S1 => new> ThreadedSend(> ' Hi '> , send);> > ThreadedSend S2 => new> ThreadedSend(> ' Bye '> , send);> > // Start two threads of ThreadedSend type> > S1.start();> > S2.start();> > // wait for threads to end> > try> {> > S1.join();> > S2.join();> > }> > catch> (Exception e) {> > System.out.println(> 'Interrupted'> );> > }> > }> }>

出力

Sending Hi Hi Sent Sending Bye Bye Sent 

プログラムを実行するたびに出力は同じになります。

説明

上の例では、ThreadedSend クラスの run() メソッド内で Sender オブジェクトを同期することを選択しています。あるいは、次のように定義することもできます。 send() ブロック全体が同期されている 同じ結果が得られます。そうすれば、ThreadedSend クラスの run() メソッド内で Message オブジェクトを同期する必要がなくなります。

// An alternate implementation to demonstrate // that we can use synchronized with method also. class Sender { public synchronized void send(String msg) { System.out.println('Sending	' + msg); try { Thread.sleep(1000); } catch (Exception e) { System.out.println('Thread interrupted.'); } System.out.println('
' + msg + 'Sent'); } } 

常にメソッド全体を同期する必要はありません。場合によっては、 メソッドの一部のみを同期する 。メソッド内の Java 同期ブロックにより、これが可能になります。

// One more alternate implementation to demonstrate // that synchronized can be used with only a part of // method class Sender { public void send(String msg) { synchronized(this) { System.out.println('Sending	' + msg ); try { Thread.sleep(1000); } catch (Exception e) { System.out.println('Thread interrupted.'); } System.out.println('
' + msg + 'Sent'); } } } 

匿名クラスを利用した同期方法の例

ジャワ




// Java Pogram to synchronized method by> // using an anonymous class> import> java.io.*;> class> Test {> > synchronized> void> test_function(> int> n)> > {> > // synchronized method> > for> (> int> i => 1> ; i <=> 3> ; i++) {> > System.out.println(n + i);> > try> {> > Thread.sleep(> 500> );> > }> > catch> (Exception e) {> > System.out.println(e);> > }> > }> > }> }> // Driver Class> public> class> GFG {> > // Main function> > public> static> void> main(String args[])> > {> > // only one object> > final> Test obj => new> Test();> > Thread a => new> Thread() {> > public> void> run() { obj.test_function(> 15> ); }> > };> > Thread b => new> Thread() {> > public> void> run() { obj.test_function(> 30> ); }> > };> > a.start();> > b.start();> > }> }>

出力

16 17 18 31 32 33