“你好,阿米戈!昨天我们讨论了多线程的好处和便利之处。现在来看一下它的缺点。遗憾的是,缺点还不小。”

以前,我们将程序视为一组调用彼此方法的对象。现在,一切都变得有点复杂。程序更像是这样一组对象,有多个“小型机器人”(线程)从其中爬过并执行方法中包含的命令。

这一新解释并不会抵消第一种解释。它们仍然是对象,并且仍然调用彼此的方法。但是我们必须记住存在多个线程,每个线程都有自己的作业或任务。

程序变得越来越复杂。不同的线程根据其所执行的任务来更改不同对象的状态。当然,它们可能会越殂代疱。

但是最糟糕的事情发生在 Java 机器深处。正如我已经说过的,表面上的线程同时性是通过处理器不断地从一个线程切换到另一个线程来实现的。它切换到一个线程,工作 10 毫秒,然后切换到下一个线程,再工作 10 毫秒,依此类推。问题就出在这里:这些切换可能在最不适当的时刻发生。请考虑以下示例:

第一个线程的代码 第二个线程的代码
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 岁
实际代码执行 第一个线程的代码 第二个线程的代码
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 方法swap name1name2 变量的值。

如果同时从两个线程中调用它会发生什么?

实际代码执行 第一个线程的代码 第二个线程的代码
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;
末行
两个变量的值都为“莉娜”。
“阿莉”对象出局。它丢失了。

“谁能想到如此简单的赋值操作会发生这种错误?!”

“是的,这个问题有解决方法。但是我们稍后再说 - 我的喉咙有点发干。”