「こんにちは、アミーゴ! 昨日はマルチスレッドの利点と利便性について話し合いました。今度は欠点を見てみましょう。残念ながら、それらは小さくありません。」

以前は、プログラムを、相互にメソッドを呼び出し合うオブジェクトのセットとして見てきました。ここで、すべてが少し複雑になります。プログラムは、複数の「小さなロボット」(スレッド) が内部を巡回し、メソッドに含まれるコマンドを実行するオブジェクトのセットに似ています。

この新しい解釈は最初の解釈を取り消すものではありません。これらは依然としてオブジェクトであり、依然として互いのメソッドを呼び出します。ただし、複数のスレッドがあり、各スレッドが独自のジョブまたはタスクを実行することを覚えておく必要があります。

プログラムはますます複雑になっています。異なるスレッドは、実行するタスクに基づいて異なるオブジェクトの状態を変更します。そして、彼らはお互いのつま先を踏み合うことができます。

しかし、最悪の事態は Java マシンの奥深くで起こります。すでに述べたように、スレッドの見かけ上の同時性は、プロセッサが常に 1 つのスレッドから別のスレッドに切り替わることによって実現されます。スレッドに切り替えて 10 ミリ秒間動作し、次のスレッドに切り替えて 10 ミリ秒間動作する、というようになります。そしてここに問題があります。これらの切り替えは最も不都合な瞬間に発生する可能性があります。次の例を考えてみましょう。

最初のスレッドのコード 2番目のスレッドのコード
System.out.print ("Nick is");
System.out.print ("");
System.out.print ("15");
System.out.print ("");
System.out.print ("years old");
System.out.println ();
System.out.print ("Lena is");
System.out.print ("");
System.out.print ("21");
System.out.print ("");
System.out.print ("years old");
System.out.println ();
表示されることを期待していたもの
ニックは15歳、
レナは21歳です。
実際のコードの実行 最初のスレッドのコード 2番目のスレッドのコード
System.out.print ("Nick is");
System.out.print ("Lena is");
System.out.print (" ");
System.out.print (" ");
System.out.print ("15");
System.out.print ("21");
System.out.print (" ");
System.out.print (" ");
System.out.print ("years old");
System.out.println ();
System.out.print ("years old");
System.out.println ();
System.out.print ("Nick is");
//other thread is running
//other thread is running
System.out.print (" ");
System.out.print ("15");
//other thread is running
//other thread is running
System.out.print (" ");
System.out.print ("years old");
System.out.println ();
//other thread is running
//other thread is running
//other thread is running
System.out.print ("Lena is");
System.out.print (" ");
//other thread is running
//other thread is running
System.out.print ("21");
System.out.print (" ");
//other thread is running
//other thread is running
//other thread is running
System.out.print ("years old");
System.out.println ();
実際に表示されるもの
ニックは レナです  15 21 

別の例を次に示します。

コード 説明
class MyClass
{
private String name1 = "Ally";
private String name2 = "Lena";
public void swap()
{
String s = name1;
name1 = name2;
name2 = s;
}
}
変数と変数swapの値を交換するメソッドです。name1name2

2 つのスレッドから同時に呼び出された場合はどうなるでしょうか?

実際のコードの実行 最初のスレッドのコード 2番目のスレッドのコード
String s1 = name1; //Ally
name1 = name2; //Lena
String s2 = name1; //Lena(!)
name1 = name2; //Lena
name2 = s1; //Ally
name2 = s2; //Lena
String s1 = name1;
name1 = name2;
//other thread is running
//other thread is running
name2 = s1;
//other thread is running
//other thread is running
//other thread is running
String s2 = name1;
name1 = name2;
//other thread is running
name2 = s2;
結論
両方の変数の値は«Lena»です。
«Ally» オブジェクトは成功しませんでした。紛失してしまいました。

「これほど単純な代入操作でこのようなエラーが発生する可能性があるとは誰が予想したでしょうか?!」

「はい、この問題には解決策があります。でも、これについては少し後で話します。喉が乾いています。」