我正在尝试运行以下代码,但无法正确获取输出 输出为
“欢迎新程序员” 但输出是 “新欢迎程序员”
class First {
public synchronized void display(String msg) {
System.out.print("["+msg);
System.out.println("]");
}
}
class Second {
String msg;
First fobj;
Second (First fp,String str) {
fobj = fp;
msg = str;
start();
}
public void run() {
synchronized(fobj) { //Synchronized block
fobj.display(msg);
}
}
}
public class SyncroBlock {
public static void main (String[] args) {
First fnew = new First();
Second ss = new Second(fnew, "welcome");
Second ss1 = new Second(fnew,"new");
Second ss2 = new Second(fnew, "programmer");
}
}
我在这里做错了什么? 有人可以纠正我吗?
答案 0 :(得分:2)
从构造函数启动线程是一个坏主意。它违反了安全施工的原则。
一个常见的错误可能是在构造过程中使此引用转义为从构造函数中启动线程。当对象从其构造函数创建线程时,几乎总是与新线程共享此引用,无论是显式(通过将其传递给构造函数)还是隐式(因为
。Thread
或Runnable
是一个拥有对象的内部类)。这样,新线程可能就可以在完全构造对象之前看到拥有对象。在构造函数中创建线程没有错,但是最好不要立即启动线程。而是公开一个
start
或initialize
方法来启动拥有的线程。从构造函数中调用可重写的实例方法(既不是private
也不是final
的实例方法,也可以允许this
引用转义。3.2.1安全的构建实践,Brian Goetz的实践中的Java并发性
Thread#start()
调用可能会花费一些时间,因此预期的"welcome -> "new" -> "programmer"
实际上可以以任意顺序 。
要执行您计划的工作,我们需要确保上一个run()
已开始执行,然后再转到下一个。对于我的机器,两次调用之间100L
的睡眠足以获得正确的顺序。
Second ss = new Second(fnew, "welcome");
Thread.sleep(100L);
Second ss1 = new Second(fnew,"new");
Thread.sleep(100L);
Second ss2 = new Second(fnew, "programmer");
这不是一个好技术,您不应该这样使用它。它使执行顺序化-我们不会从多线程中获得任何好处。
答案 1 :(得分:0)
我认为您忘了实现Callable或Runnable或实现第二类所需的任何东西。