即使我们在 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
Following code executes but I want it to print a new String tmp
of the same length as sample
's length.
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);
}
}
Here are some sample outputs:
Mnla
Maniplua
Mpia
Miap
Mu
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,您需要知道两件事:
修改字符串总是创建一个新字符串并丢弃
前一个
+=
不是单个操作 - 它是三个操作(读取、修改、写回)。
您可以想象在您的代码中,当两个线程同时读取字符串时,它们读取相同的值(例如“Man”)。然后第一个线程创建一个新字符串(添加自己的字母,例如“Mani”),第二个线程创建另一个新字符串(例如“Manp”)。现在他们都将对新值的引用放入字段
tmp
中;根据哪一个“获胜”,其中一个字符将永远不会被其他线程看到。请注意,在“真实”程序中,问题更加复杂(优化开始),您确实需要了解 Java 内存模型才能编写正确的代码。要解决您的问题,您需要:
停止使用字符串(它们无法修改,新字符串需要采用
他们的位置),使用存储字符的可变对象;一个
所有线程都可以看到并且可以写入的单个对象;
确保该对象在与以下对象一起使用时“行为正确”
多线程(在 Java 中,这意味着该对象是
并发或同步)
实际上,Java 有一个非常古老的类(现在很少使用)非常适合您的情况: StringBuffer。
使用
StringBuffer
而不是String
作为您的tmp
;然后使用append('x')
而不是+= 'x'
来添加字符。Firstly, you need to know two things:
modifying a string is always creating a new string and discarding the
former one
+=
is not a single operation - it's three operations(read, modify, write back).
You can imagine that in your code, when two threads read the string at the same time, they read the same value (e.g. "Man"). Then the first thread creates a new string (adding its own letter, e.g. "Mani") and the second thread creates another new string (e.g. "Manp"). Now they both put the reference to their new value into the field
tmp
; depending on which one "wins", one of the chars will never be seen by other threads. Note that in "real" programs the issue is more complex (optimization kicks in) and you really need to understand the Java Memory Model to write correct code.To fix your problem, you need to:
Stop using strings (they cannot be modified, new strings need to take
their places), use instead a mutable object that stores characters; a
single object that all the threads see and can write to;
Make sure that this object "behaves correctly" when used with
multiple threads (in Java, this means that the object is either
concurrent or synchronized)
Actually, Java has a very old class (seldom used nowadays) that is perfect for your case: a StringBuffer.
Use a
StringBuffer
instead of aString
for yourtmp
; then useappend('x')
instead of+= 'x'
for adding chars.请告诉我们您期望从代码中获得什么输出。
一般来说:
在您的实现中,您确实启动了 10 个线程(因为您的
sample
字符串有 10 个字母)。但此时你完全无法控制线程的执行顺序以及tmp
变量的状态。这可能会导致字母和字母的混合顺序相互覆盖(如输出中所示)。
一旦您指定了您期望的输出,就可以提出解决方案。
Please tell us what output you expect from your code.
Generally spoken:
With your implementation you do start 10 threads (because your
sample
string has 10 letters). But you have absolutely no control over the order in which the threads are executed and the state of thetmp
variable at this time.This could cause mixed order of letter and letters overwriting one another (like seen in your output).
Once you specify what output you expect it will be possible to suggest a solution.