即使我们在for循环中创建了一个新线程,如何让所有线程都能工作


执行以下代码,但我希望它打印一个与sample长度相同的新字符串tmp
class T10 {
static String tmp = "", sample = "Manipulate";
public static void main(String args[]) {
for(int i=0;i<sample.length();i++)
new Thread10(i).t.start();
System.out.println(tmp);
}
}
class Thread10 implements Runnable {
int i;
Thread t;
Thread10(int i) {
t = new Thread(this, "Manipulator Thread : "+i);
this.i = i;
}
public void run() {
T10.tmp+=T10.sample.charAt(i);
}
}

以下是一些示例输出:

Mnla
Maniplua
Mpia
Miap
Mu

首先,您需要了解两件事:

  • 不能在Java中更改字符串。代码看起来像修改字符串总是创建一个新字符串并丢弃前一个
  • +=不是单一操作,而是三个操作(读取、修改、回写(

您可以想象,在您的代码中,当两个线程同时读取字符串时,它们读取的值相同(例如"Man"(。然后第一个线程创建一个新的字符串(添加它自己的字母,例如"Mani"(,第二个线程创建另一个新字符串(例如"Manp"(。现在,他们都将对其新值的引用放入字段tmp;取决于哪一个";获胜";,其中一个字符将永远不会被其他线程看到。注意,在";真实的";程序中,问题更复杂(优化开始(,您确实需要了解Java内存模型才能编写正确的代码。

要解决您的问题,您需要:

  • 停止使用字符串(不能修改,需要使用新字符串它们的位置(,而是使用存储字符的可变对象;一所有线程都可以看到并写入的单个对象;

  • 确保该对象";行为正确";与一起使用时多个线程(在Java中,这意味着对象是并发或同步(

实际上,Java有一个非常古老的类(现在很少使用(,非常适合您的情况:StringBuffer。

使用StringBuffer而不是String作为tmp;则使用CCD_ 8而不是CCD_。

请告诉我们您希望从代码中得到什么输出。

一般来说:

在您的实现中,您确实启动了10个线程(因为sample字符串有10个字母(。但是,您绝对无法控制线程的执行顺序和此时tmp变量的状态。

这可能会导致字母和字母的混合顺序相互覆盖(如输出中所示(。

一旦您指定了期望的输出,就可以提出解决方案。

最新更新