synchronizedブロック
日本語 | 同期囲み |
英語 | synchronized block |
ふりがな | しんくろないずどぶろっく |
フリガナ | シンクロナイズドブロック |
同期を取るブロック。
synchronizedで修飾されたブロック。「synchronized( 対象の参照型変数 ){ 実装 }」のように、ブロックの前にsynchronizedを付け、対象の変数を指定したもの。
マルチスレッドにおいて、複数のスレッドが同時に処理することのできないブロック。
synchronizedブロックは、処理するスレッドを1つに限定することができる。2つのスレッドからほぼ同時に実行された場合、先にブロック内に入った側がブロックから抜けない限り、後から入ろうとした側が待たされる。
ただし、synchronizedブロックは、その「対象の参照型変数」が指し示すインスタンスが異なる場合には機能しない。つまりsynchronizedブロックは、対象のインスタンスが同じ場合にのみ待たせることができ、異なる場合には待たせない。
これは、synchronizedブロックが「特定のインスタンスの同期を取る」ためのものだからである。複数のスレッドが同時にアクセスすると、先のスレッドがインスタンスの情報を書き換える前に後のスレッドがインスタンスの情報を読み取り、値が誤ったものになってしまう可能性があるからである。
synchronizedブロックはそれを防ぐためのものである。インスタンスにアクセスする箇所をsynchronizedブロックとすることで、先のスレッドがブロック内を処理し終えるまで後のスレッドを待たせることができる。それにより、インスタンスの値を常に保つことができる。
インスタンスが異なれば同期を取る必要はない。インスタンスが異なるとsynchronizedブロックが機能しないのはこのためである。
また、この目的のため、synchronizedブロックは全て同期の対象となる。
synchronizedブロックが複数存在する場合、同じように機能する。synchronizedブロックAがスレッド1に処理されている間に、synchronizedブロックBをスレッド2が処理しようとした場合、スレッド1がsynchronizedブロックAを通り過ぎるまで待たされる。
synchronizedブロックを使用することで同期を取ることができるが、待ち時間が生じるため、動作に時間が掛かる可能性がある。
synchronizedブロック以外にも、同期を取る機能としてsynchronizedスレッドがある。
synchronizedメソッドは、synchronizedブロックをthisに対して行うものであり、自クラスのフィールドに対して排他制御を行いたい場合にはsynchronizedメソッドの方がいいだろう。
synchronizedで修飾されたブロック。「synchronized( 対象の参照型変数 ){ 実装 }」のように、ブロックの前にsynchronizedを付け、対象の変数を指定したもの。
マルチスレッドにおいて、複数のスレッドが同時に処理することのできないブロック。
synchronizedブロックは、処理するスレッドを1つに限定することができる。2つのスレッドからほぼ同時に実行された場合、先にブロック内に入った側がブロックから抜けない限り、後から入ろうとした側が待たされる。
ただし、synchronizedブロックは、その「対象の参照型変数」が指し示すインスタンスが異なる場合には機能しない。つまりsynchronizedブロックは、対象のインスタンスが同じ場合にのみ待たせることができ、異なる場合には待たせない。
これは、synchronizedブロックが「特定のインスタンスの同期を取る」ためのものだからである。複数のスレッドが同時にアクセスすると、先のスレッドがインスタンスの情報を書き換える前に後のスレッドがインスタンスの情報を読み取り、値が誤ったものになってしまう可能性があるからである。
synchronizedブロックはそれを防ぐためのものである。インスタンスにアクセスする箇所をsynchronizedブロックとすることで、先のスレッドがブロック内を処理し終えるまで後のスレッドを待たせることができる。それにより、インスタンスの値を常に保つことができる。
インスタンスが異なれば同期を取る必要はない。インスタンスが異なるとsynchronizedブロックが機能しないのはこのためである。
また、この目的のため、synchronizedブロックは全て同期の対象となる。
synchronizedブロックが複数存在する場合、同じように機能する。synchronizedブロックAがスレッド1に処理されている間に、synchronizedブロックBをスレッド2が処理しようとした場合、スレッド1がsynchronizedブロックAを通り過ぎるまで待たされる。
synchronizedブロックを使用することで同期を取ることができるが、待ち時間が生じるため、動作に時間が掛かる可能性がある。
synchronizedブロック以外にも、同期を取る機能としてsynchronizedスレッドがある。
synchronizedメソッドは、synchronizedブロックをthisに対して行うものであり、自クラスのフィールドに対して排他制御を行いたい場合にはsynchronizedメソッドの方がいいだろう。
参考サイト
- (参考サイトはありません)
// Sample.java
public class Sample
{
public static void main( String[] args )
{
try
{
// データクラス。
DataClass data = new DataClass();
// 別スレッドの方を呼び出します。
OtherThread thread = new OtherThread( data );
thread.start();
// 2秒待ちます。OtherThreadの方を先に
// 実行するためです。
Thread.sleep( 2 * 1000 );
// こちらでも。
System.out.println( "Sample開始" );
// synchronizedブロックを持つメソッドを呼び出します。
SynchronizeClass synchronizeClass = new SynchronizeClass();
synchronizeClass.methodHasSynchronizedBlock( "Sample", data );
System.out.println( "Sample終了" );
// OtherThread開始
// synchronizedブロック開始 from OtherThread
// Sample開始
// synchronizedブロック終了 from OtherThread
// synchronizedブロック開始 from Sample
// OtherThread終了
// synchronizedブロック終了 from Sample
// Sample終了
// このように、synchronizedブロックは、
// 一度に1つのスレッドでしか処理できません。
// 先に呼び出した方が終了するまで待ちます。
// synchronizedブロックの排他処理は、インスタンスに
// 対して行われます。そのため、同じsynchronizedメソッドでも、
// 対象のインスタンスが異なれば排他されません。
thread = new OtherThread( data );
thread.start();
// 2秒待ちます。OtherThreadの方を先に
// 実行するためです。
Thread.sleep( 2 * 1000 );
// こちらでも。
System.out.println( "Sample開始" );
// synchronizedブロックを持つメソッドを呼び出します。
// ただし、別のデータクラスを渡します。
synchronizeClass.methodHasSynchronizedBlock( "Sample", new DataClass() );
System.out.println( "Sample終了" );
// OtherThread開始
// synchronizedブロック開始 from OtherThread
// Sample開始
// synchronizedブロック開始 from Sample
// synchronizedブロック終了 from OtherThread
// OtherThread終了
// synchronizedブロック終了 from Sample
// Sample終了
// このように、インスタンスが異なれば排他されません。
// インスタンスが同じであれば、全てのsynchronizedブロックが
// 排他されます。
thread = new OtherThread( data );
thread.start();
// 2秒待ちます。OtherThreadの方を先に
// 実行するためです。
Thread.sleep( 2 * 1000 );
// こちらでも。
System.out.println( "Sample開始" );
// もうひとつのsynchronizedブロックを持つメソッドを呼び出します。
synchronizeClass.methodHasSynchronizedBlock2( "Sample", data );
System.out.println( "Sample終了" );
// OtherThread開始
// synchronizedブロック開始 from OtherThread
// Sample開始
// synchronizedブロック終了 from OtherThread
// OtherThread終了
// synchronizedブロック2開始 from Sample
// synchronizedブロック2終了 from Sample
// Sample終了
// このように、全く異なるブロックでも、対象の
// インスタンスが同じであれば同期が取られます。
}
catch( InterruptedException e )
{
// sleep()メソッドが途中で中断されると
// InterruptedException例外が投げられます。
// 滅多にないですが。
e.printStackTrace();
}
}
}
/**
* 別スレッドとして実行するためのクラス。
*/
class OtherThread extends Thread
{
/** データクラス。 */
private DataClass data;
/** コンストラクタ。 */
public OtherThread( DataClass data )
{
this.data = data;
}
/**
* Threadクラスのrun()メソッドを
* オーバーライドしたメソッド。このメソッドが
* 別スレッドとして呼び出されます。
*/
public void run()
{
System.out.println( "OtherThread開始" );
// synchronizedブロックを持つメソッドを呼び出します。
SynchronizeClass synchronizeClass = new SynchronizeClass();
synchronizeClass.methodHasSynchronizedBlock( "OtherThread", data );
System.out.println( "OtherThread終了" );
}
}
/**
* 同期処理テスト用クラス。
*/
class SynchronizeClass
{
/**
* synchronizedブロックを持つメソッド
*/
public void methodHasSynchronizedBlock( String name, DataClass data )
{
try
{
synchronized( data )
{
System.out.println( "synchronizedブロック開始 from " + name );
// 5秒待ちます。
Thread.sleep( 5 * 1000 );
System.out.println( "synchronizedブロック終了 from " + name );
// たとえば、dataにアクセスする場合。
data.setData( 100 );
// synchronizedによる同期は、この「インスタンスへのアクセス」を
// 1スレッドに限定するためのものです。だから、
// このdataの実際のインスタンスが異なる場合には同期が
// 取られないのです。
}
}
catch( InterruptedException e )
{
// sleep()メソッドが途中で中断されると
// InterruptedException例外が投げられます。
// 滅多にないですが。
e.printStackTrace();
}
}
/**
* もうひとつのsynchronizedブロックを持つメソッド
*/
public void methodHasSynchronizedBlock2( String name, DataClass data )
{
try
{
synchronized( data )
{
System.out.println( "synchronizedブロック2開始 from " + name );
// 5秒待ちます。
Thread.sleep( 5 * 1000 );
System.out.println( "synchronizedブロック2終了 from " + name );
// たとえば、dataにアクセスする場合。
data.setData( 100 );
// synchronizedによる同期は、この「インスタンスへのアクセス」を
// 1スレッドに限定するためのものです。だから、
// このdataの実際のインスタンスが異なる場合には同期が
// 取られないのです。
}
}
catch( InterruptedException e )
{
// sleep()メソッドが途中で中断されると
// InterruptedException例外が投げられます。
// 滅多にないですが。
e.printStackTrace();
}
// synchronizedブロックが対象にできる変数は、
// 参照型変数のみです。
// int i = 100;
// synchronized( i ){}
// コンパイルエラー:
// int は synchronized 文に対して有効な型の引き数ではありません。
}
}
/**
* データクラス。
*/
class DataClass
{
/**
* privateなフィールド。
*/
private int data;
/**
* getter。
*/
public int getData()
{
return data;
}
/**
* setter。
*/
public void setData( int value )
{
this.data = value;
}
}
public class Sample
{
public static void main( String[] args )
{
try
{
// データクラス。
DataClass data = new DataClass();
// 別スレッドの方を呼び出します。
OtherThread thread = new OtherThread( data );
thread.start();
// 2秒待ちます。OtherThreadの方を先に
// 実行するためです。
Thread.sleep( 2 * 1000 );
// こちらでも。
System.out.println( "Sample開始" );
// synchronizedブロックを持つメソッドを呼び出します。
SynchronizeClass synchronizeClass = new SynchronizeClass();
synchronizeClass.methodHasSynchronizedBlock( "Sample", data );
System.out.println( "Sample終了" );
// OtherThread開始
// synchronizedブロック開始 from OtherThread
// Sample開始
// synchronizedブロック終了 from OtherThread
// synchronizedブロック開始 from Sample
// OtherThread終了
// synchronizedブロック終了 from Sample
// Sample終了
// このように、synchronizedブロックは、
// 一度に1つのスレッドでしか処理できません。
// 先に呼び出した方が終了するまで待ちます。
// synchronizedブロックの排他処理は、インスタンスに
// 対して行われます。そのため、同じsynchronizedメソッドでも、
// 対象のインスタンスが異なれば排他されません。
thread = new OtherThread( data );
thread.start();
// 2秒待ちます。OtherThreadの方を先に
// 実行するためです。
Thread.sleep( 2 * 1000 );
// こちらでも。
System.out.println( "Sample開始" );
// synchronizedブロックを持つメソッドを呼び出します。
// ただし、別のデータクラスを渡します。
synchronizeClass.methodHasSynchronizedBlock( "Sample", new DataClass() );
System.out.println( "Sample終了" );
// OtherThread開始
// synchronizedブロック開始 from OtherThread
// Sample開始
// synchronizedブロック開始 from Sample
// synchronizedブロック終了 from OtherThread
// OtherThread終了
// synchronizedブロック終了 from Sample
// Sample終了
// このように、インスタンスが異なれば排他されません。
// インスタンスが同じであれば、全てのsynchronizedブロックが
// 排他されます。
thread = new OtherThread( data );
thread.start();
// 2秒待ちます。OtherThreadの方を先に
// 実行するためです。
Thread.sleep( 2 * 1000 );
// こちらでも。
System.out.println( "Sample開始" );
// もうひとつのsynchronizedブロックを持つメソッドを呼び出します。
synchronizeClass.methodHasSynchronizedBlock2( "Sample", data );
System.out.println( "Sample終了" );
// OtherThread開始
// synchronizedブロック開始 from OtherThread
// Sample開始
// synchronizedブロック終了 from OtherThread
// OtherThread終了
// synchronizedブロック2開始 from Sample
// synchronizedブロック2終了 from Sample
// Sample終了
// このように、全く異なるブロックでも、対象の
// インスタンスが同じであれば同期が取られます。
}
catch( InterruptedException e )
{
// sleep()メソッドが途中で中断されると
// InterruptedException例外が投げられます。
// 滅多にないですが。
e.printStackTrace();
}
}
}
/**
* 別スレッドとして実行するためのクラス。
*/
class OtherThread extends Thread
{
/** データクラス。 */
private DataClass data;
/** コンストラクタ。 */
public OtherThread( DataClass data )
{
this.data = data;
}
/**
* Threadクラスのrun()メソッドを
* オーバーライドしたメソッド。このメソッドが
* 別スレッドとして呼び出されます。
*/
public void run()
{
System.out.println( "OtherThread開始" );
// synchronizedブロックを持つメソッドを呼び出します。
SynchronizeClass synchronizeClass = new SynchronizeClass();
synchronizeClass.methodHasSynchronizedBlock( "OtherThread", data );
System.out.println( "OtherThread終了" );
}
}
/**
* 同期処理テスト用クラス。
*/
class SynchronizeClass
{
/**
* synchronizedブロックを持つメソッド
*/
public void methodHasSynchronizedBlock( String name, DataClass data )
{
try
{
synchronized( data )
{
System.out.println( "synchronizedブロック開始 from " + name );
// 5秒待ちます。
Thread.sleep( 5 * 1000 );
System.out.println( "synchronizedブロック終了 from " + name );
// たとえば、dataにアクセスする場合。
data.setData( 100 );
// synchronizedによる同期は、この「インスタンスへのアクセス」を
// 1スレッドに限定するためのものです。だから、
// このdataの実際のインスタンスが異なる場合には同期が
// 取られないのです。
}
}
catch( InterruptedException e )
{
// sleep()メソッドが途中で中断されると
// InterruptedException例外が投げられます。
// 滅多にないですが。
e.printStackTrace();
}
}
/**
* もうひとつのsynchronizedブロックを持つメソッド
*/
public void methodHasSynchronizedBlock2( String name, DataClass data )
{
try
{
synchronized( data )
{
System.out.println( "synchronizedブロック2開始 from " + name );
// 5秒待ちます。
Thread.sleep( 5 * 1000 );
System.out.println( "synchronizedブロック2終了 from " + name );
// たとえば、dataにアクセスする場合。
data.setData( 100 );
// synchronizedによる同期は、この「インスタンスへのアクセス」を
// 1スレッドに限定するためのものです。だから、
// このdataの実際のインスタンスが異なる場合には同期が
// 取られないのです。
}
}
catch( InterruptedException e )
{
// sleep()メソッドが途中で中断されると
// InterruptedException例外が投げられます。
// 滅多にないですが。
e.printStackTrace();
}
// synchronizedブロックが対象にできる変数は、
// 参照型変数のみです。
// int i = 100;
// synchronized( i ){}
// コンパイルエラー:
// int は synchronized 文に対して有効な型の引き数ではありません。
}
}
/**
* データクラス。
*/
class DataClass
{
/**
* privateなフィールド。
*/
private int data;
/**
* getter。
*/
public int getData()
{
return data;
}
/**
* setter。
*/
public void setData( int value )
{
this.data = value;
}
}
// Sample.java public class Sample { public static void main( String[] args ) { try { // データクラス。 DataClass data = new DataClass(); // 別スレッドの方を呼び出します。 OtherThread thread = new OtherThread( data ); thread.start(); // 2秒待ちます。OtherThreadの方を先に // 実行するためです。 Thread.sleep( 2 * 1000 ); // こちらでも。 System.out.println( "Sample開始" ); // synchronizedブロックを持つメソッドを呼び出します。 SynchronizeClass synchronizeClass = new SynchronizeClass(); synchronizeClass.methodHasSynchronizedBlock( "Sample", data ); System.out.println( "Sample終了" ); // OtherThread開始 // synchronizedブロック開始 from OtherThread // Sample開始 // synchronizedブロック終了 from OtherThread // synchronizedブロック開始 from Sample // OtherThread終了 // synchronizedブロック終了 from Sample // Sample終了 // このように、synchronizedブロックは、 // 一度に1つのスレッドでしか処理できません。 // 先に呼び出した方が終了するまで待ちます。 // synchronizedブロックの排他処理は、インスタンスに // 対して行われます。そのため、同じsynchronizedメソッドでも、 // 対象のインスタンスが異なれば排他されません。 thread = new OtherThread( data ); thread.start(); // 2秒待ちます。OtherThreadの方を先に // 実行するためです。 Thread.sleep( 2 * 1000 ); // こちらでも。 System.out.println( "Sample開始" ); // synchronizedブロックを持つメソッドを呼び出します。 // ただし、別のデータクラスを渡します。 synchronizeClass.methodHasSynchronizedBlock( "Sample", new DataClass() ); System.out.println( "Sample終了" ); // OtherThread開始 // synchronizedブロック開始 from OtherThread // Sample開始 // synchronizedブロック開始 from Sample // synchronizedブロック終了 from OtherThread // OtherThread終了 // synchronizedブロック終了 from Sample // Sample終了 // このように、インスタンスが異なれば排他されません。 // インスタンスが同じであれば、全てのsynchronizedブロックが // 排他されます。 thread = new OtherThread( data ); thread.start(); // 2秒待ちます。OtherThreadの方を先に // 実行するためです。 Thread.sleep( 2 * 1000 ); // こちらでも。 System.out.println( "Sample開始" ); // もうひとつのsynchronizedブロックを持つメソッドを呼び出します。 synchronizeClass.methodHasSynchronizedBlock2( "Sample", data ); System.out.println( "Sample終了" ); // OtherThread開始 // synchronizedブロック開始 from OtherThread // Sample開始 // synchronizedブロック終了 from OtherThread // OtherThread終了 // synchronizedブロック2開始 from Sample // synchronizedブロック2終了 from Sample // Sample終了 // このように、全く異なるブロックでも、対象の // インスタンスが同じであれば同期が取られます。 } catch( InterruptedException e ) { // sleep()メソッドが途中で中断されると // InterruptedException例外が投げられます。 // 滅多にないですが。 e.printStackTrace(); } } } /** * 別スレッドとして実行するためのクラス。 */ class OtherThread extends Thread { /** データクラス。 */ private DataClass data; /** コンストラクタ。 */ public OtherThread( DataClass data ) { this.data = data; } /** * Threadクラスのrun()メソッドを * オーバーライドしたメソッド。このメソッドが * 別スレッドとして呼び出されます。 */ public void run() { System.out.println( "OtherThread開始" ); // synchronizedブロックを持つメソッドを呼び出します。 SynchronizeClass synchronizeClass = new SynchronizeClass(); synchronizeClass.methodHasSynchronizedBlock( "OtherThread", data ); System.out.println( "OtherThread終了" ); } } /** * 同期処理テスト用クラス。 */ class SynchronizeClass { /** * synchronizedブロックを持つメソッド */ public void methodHasSynchronizedBlock( String name, DataClass data ) { try { synchronized( data ) { System.out.println( "synchronizedブロック開始 from " + name ); // 5秒待ちます。 Thread.sleep( 5 * 1000 ); System.out.println( "synchronizedブロック終了 from " + name ); // たとえば、dataにアクセスする場合。 data.setData( 100 ); // synchronizedによる同期は、この「インスタンスへのアクセス」を // 1スレッドに限定するためのものです。だから、 // このdataの実際のインスタンスが異なる場合には同期が // 取られないのです。 } } catch( InterruptedException e ) { // sleep()メソッドが途中で中断されると // InterruptedException例外が投げられます。 // 滅多にないですが。 e.printStackTrace(); } } /** * もうひとつのsynchronizedブロックを持つメソッド */ public void methodHasSynchronizedBlock2( String name, DataClass data ) { try { synchronized( data ) { System.out.println( "synchronizedブロック2開始 from " + name ); // 5秒待ちます。 Thread.sleep( 5 * 1000 ); System.out.println( "synchronizedブロック2終了 from " + name ); // たとえば、dataにアクセスする場合。 data.setData( 100 ); // synchronizedによる同期は、この「インスタンスへのアクセス」を // 1スレッドに限定するためのものです。だから、 // このdataの実際のインスタンスが異なる場合には同期が // 取られないのです。 } } catch( InterruptedException e ) { // sleep()メソッドが途中で中断されると // InterruptedException例外が投げられます。 // 滅多にないですが。 e.printStackTrace(); } // synchronizedブロックが対象にできる変数は、 // 参照型変数のみです。 // int i = 100; // synchronized( i ){} // コンパイルエラー: // int は synchronized 文に対して有効な型の引き数ではありません。 } } /** * データクラス。 */ class DataClass { /** * privateなフィールド。 */ private int data; /** * getter。 */ public int getData() { return data; } /** * setter。 */ public void setData( int value ) { this.data = value; } }