以下是代码。输出为1000,b = 1000。我不明白为什么m2()每次都会先运行。
public class TT implements Runnable{
int b = 100;
public synchronized void m1() throws Exception {
b = 1000;
Thread.sleep(100);
System.out.println("b =" + b);
}
public synchronized void m2() throws Exception {
Thread.sleep(2000);
b = 2000;
}
public void run() {
try {
m1();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
TT tt = new TT();
Thread t = new Thread(tt);
t.start();// m1() starts
tt.m2();// m2() starts
System.out.println(tt.b);
}
}
答案 0 :(得分:3)
真实原因 1 synchronized
关键字。
m2()
方法获取TT
实例上的锁,然后休眠。同时,线程开始生效,run()
方法尝试调用m1()
。但是m1()
必须等到对m2()
的调用完成并释放锁定。
现在,如果新线程已启动并设法在现有线程调用m1()
之前调用m2()
,那么您将以其他顺序查看事件。这在理论上是可行的......但在典型的Java平台上不太可能。 (通常,父线程在启动子线程时不会被取消调度。)
m2()
返回后会发生什么情况将决定您看到的输出。由于您直接访问tt.b
(没有任何同步),从理论角度来看结果是不可预测的。
基本上,这只是说明sleep
是进行线程调度的错误方法。如果您希望一个线程上的一个事件发生在另一个事件上的另一个事件之前,则线程需要显式协调。依赖睡眠和偶然的时间效应(如thread.start()
通常需要很长时间)会给你不可靠的行为。
1 - 显然,它是一组事物。但是sleep
hackery的真正原因是synchronized
关键字无效。
答案 1 :(得分:1)
Starting a thread takes a while。已经执行的现有线程具有很大的优势,它已经存在并且只需要获取锁,另一个线程依赖于在获取锁之前创建新线程。一个线程只需要获得一个锁来赢得比赛,关闭另一个线程,不必从头开始创建的线程很可能首先到达那里。
这仍然是一种竞争条件,你不应该编写依赖于谁先到达那里的代码。
答案 2 :(得分:1)
如果你想在t thread
完成它的工作后运行tt.m2()。在t.join()
之后添加t.start()
。这使得主线程在t
完成其工作后运行。