volatile
日本語 | 揮発性 |
英語 | volatile |
ふりがな | ぼらたいる |
フリガナ | ボラタイル |
マルチスレッド時に、フィールドの「命令単位」での同期を取るための予約語。
フィールドに対して++演算子や--演算子によるアクセスを行う場合、フィールドへのアクセスは「1回」でできるため、同期を取る必要はないように見える。
だが、実際にはそうではない。++演算子等は、実際には「値の読み取り」「値の増加」「値の書き込み」といった手順を踏む。
マルチスレッドの場合、この3つの処理を同一のフィールドに対して複数のスレッドが同時に行った場合、同期が取られず、値が誤った値に変えられてしまう。
volatileをフィールドに付けることで、この問題が解決される。++演算子や--演算子によるアクセスを、同時に複数のスレッドが行おうとしてもその処理が終わるまでは他のスレッドが処理できないようになる。
ただし、使用はあまり勧められない。
この問題は、++演算子等の「読み取りと書き込みが同時に行われる」場合にのみ当てはまる。ほとんどの場合、読み取りと書き込みは別に行われ、その場合には通常の同期処理が必要となる。
また、volatileは実際には実装されていない場合があり、その場合は機能しない。
フィールドに対して++演算子や--演算子によるアクセスを行う場合、フィールドへのアクセスは「1回」でできるため、同期を取る必要はないように見える。
だが、実際にはそうではない。++演算子等は、実際には「値の読み取り」「値の増加」「値の書き込み」といった手順を踏む。
マルチスレッドの場合、この3つの処理を同一のフィールドに対して複数のスレッドが同時に行った場合、同期が取られず、値が誤った値に変えられてしまう。
volatileをフィールドに付けることで、この問題が解決される。++演算子や--演算子によるアクセスを、同時に複数のスレッドが行おうとしてもその処理が終わるまでは他のスレッドが処理できないようになる。
ただし、使用はあまり勧められない。
この問題は、++演算子等の「読み取りと書き込みが同時に行われる」場合にのみ当てはまる。ほとんどの場合、読み取りと書き込みは別に行われ、その場合には通常の同期処理が必要となる。
また、volatileは実際には実装されていない場合があり、その場合は機能しない。
参考サイト
- (参考サイトはありません)
// Sample.java
public class Sample
{
public static void main( String[] args )
{
OtherThread thread = new OtherThread();
// もうひとつスレッド(スレッドB)を作ります。
// 同時に2スレッドでアクセスします。
thread.start();
for( int iF1 = 0; iF1 < 10000000; ++iF1 )
{
thread.notVolatileData++;
thread.volatileData++;
}
try
{
// 終わるまで待ちます。
while( thread.isCompleted == false )
{
Thread.sleep( 1 * 1000 );
}
System.out.println( "notVolatileData: " + thread.notVolatileData );
System.out.println( "volatileData: " + thread.volatileData );
// notVolatileData: 15802931
// volatileData: 20000001
// このように、volatileなフィールドはアクセス時に同期が取られます。
// ……と言っといてなんですが、ほとんどのJava実行環境はvolatileを
// サポートしていないので、両方とも結果が変わる可能性があります。
// どちらにしろ、volatileは過信しない方がいいでしょう。
// この場合であればsynchronizedで同期を取ってフィールドにアクセスしましょう。
}
catch( InterruptedException e )
{
// sleep()メソッドが途中で中断されると
// InterruptedException例外が投げられます。
e.printStackTrace();
}
}
}
/**
* 別スレッドとして実行するためのクラス。
*/
class OtherThread extends Thread
{
/** 普通のフィールド */
public int notVolatileData = 1;
/** volatileフィールド。 */
public volatile int volatileData = 1;
/** 終了フラグ */
public boolean isCompleted = false;
/**
* Threadクラスのrun()メソッドを
* オーバーライドしたメソッド。このメソッドが
* 別スレッドとして呼び出されます。
*/
public void run()
{
for( int iF1 = 0; iF1 < 10000000; ++iF1 )
{
notVolatileData++;
volatileData++;
}
isCompleted = true;
}
}
public class Sample
{
public static void main( String[] args )
{
OtherThread thread = new OtherThread();
// もうひとつスレッド(スレッドB)を作ります。
// 同時に2スレッドでアクセスします。
thread.start();
for( int iF1 = 0; iF1 < 10000000; ++iF1 )
{
thread.notVolatileData++;
thread.volatileData++;
}
try
{
// 終わるまで待ちます。
while( thread.isCompleted == false )
{
Thread.sleep( 1 * 1000 );
}
System.out.println( "notVolatileData: " + thread.notVolatileData );
System.out.println( "volatileData: " + thread.volatileData );
// notVolatileData: 15802931
// volatileData: 20000001
// このように、volatileなフィールドはアクセス時に同期が取られます。
// ……と言っといてなんですが、ほとんどのJava実行環境はvolatileを
// サポートしていないので、両方とも結果が変わる可能性があります。
// どちらにしろ、volatileは過信しない方がいいでしょう。
// この場合であればsynchronizedで同期を取ってフィールドにアクセスしましょう。
}
catch( InterruptedException e )
{
// sleep()メソッドが途中で中断されると
// InterruptedException例外が投げられます。
e.printStackTrace();
}
}
}
/**
* 別スレッドとして実行するためのクラス。
*/
class OtherThread extends Thread
{
/** 普通のフィールド */
public int notVolatileData = 1;
/** volatileフィールド。 */
public volatile int volatileData = 1;
/** 終了フラグ */
public boolean isCompleted = false;
/**
* Threadクラスのrun()メソッドを
* オーバーライドしたメソッド。このメソッドが
* 別スレッドとして呼び出されます。
*/
public void run()
{
for( int iF1 = 0; iF1 < 10000000; ++iF1 )
{
notVolatileData++;
volatileData++;
}
isCompleted = true;
}
}
// Sample.java public class Sample { public static void main( String[] args ) { OtherThread thread = new OtherThread(); // もうひとつスレッド(スレッドB)を作ります。 // 同時に2スレッドでアクセスします。 thread.start(); for( int iF1 = 0; iF1 < 10000000; ++iF1 ) { thread.notVolatileData++; thread.volatileData++; } try { // 終わるまで待ちます。 while( thread.isCompleted == false ) { Thread.sleep( 1 * 1000 ); } System.out.println( "notVolatileData: " + thread.notVolatileData ); System.out.println( "volatileData: " + thread.volatileData ); // notVolatileData: 15802931 // volatileData: 20000001 // このように、volatileなフィールドはアクセス時に同期が取られます。 // ……と言っといてなんですが、ほとんどのJava実行環境はvolatileを // サポートしていないので、両方とも結果が変わる可能性があります。 // どちらにしろ、volatileは過信しない方がいいでしょう。 // この場合であればsynchronizedで同期を取ってフィールドにアクセスしましょう。 } catch( InterruptedException e ) { // sleep()メソッドが途中で中断されると // InterruptedException例外が投げられます。 e.printStackTrace(); } } } /** * 別スレッドとして実行するためのクラス。 */ class OtherThread extends Thread { /** 普通のフィールド */ public int notVolatileData = 1; /** volatileフィールド。 */ public volatile int volatileData = 1; /** 終了フラグ */ public boolean isCompleted = false; /** * Threadクラスのrun()メソッドを * オーバーライドしたメソッド。このメソッドが * 別スレッドとして呼び出されます。 */ public void run() { for( int iF1 = 0; iF1 < 10000000; ++iF1 ) { notVolatileData++; volatileData++; } isCompleted = true; } }