java多线程锁的问题,请高手解释代码,最好结合执行时内存图解释

来源:百度知道 编辑:UC知道 时间:2024/09/28 12:33:14
请看代码:
public class TT implements Runnable {
int b = 100;
public synchronized void m1() throws Exception{
b = 1000;
Thread.sleep(5000);
System.out.println("b = " + b);
}
public synchronized void m2() throws Exception {
/*这里改变睡眠时间的值,比方说改成1000或者7000就会影响到下面tt.b值的输出结果*/
Thread.sleep(2500);
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();

tt.m2();
System.out.println(tt.b);
//这里的b值取决于m2()方法中的睡眠时间。
}
}
请高手解释下为什么m2()方法中sleep()的取值不同时,tt.b的值也会不同?不是锁m1()tt.b输出的值应该是m1方法中的b的值吗?请结合执行时内存变化图解释下,谢谢。
这是尚学堂的例子,我用Eclipse运行这个程序,当我修改m2()的睡眠值为sleep(1000)时,程序输出的结果是:2000 b=1000 当我把m2()方法中的睡眠值修改为sleep(2500)时,输出结果就为:1000 b=1000。知道原因的高手请指教。
视频中马士兵

给马士兵发了个邮件,他的回答是:

线程执行的先后顺序不固定。

你的synchronized 是对方法枷锁,而不是对象加锁,由于使用线程默认优先级(启动的线程为当前线程的子线程,由于默认,和主线程优先级相同),在t.start();启动后,内部也就是执行m1()的时候,tt.m2()也在执行,如果时间不同,谁先执行修改就不一定了,所以最后结果不一致。

这个例子其实你不用改任何代码多运行几次也能看到不同的结果,这是因为线程调度的不确定性,也就导致了线程执行顺序的不确定性。
你不用去改任何睡眠时间,这个例子个人觉得不好,如果只是介绍线程的概念,不必要引入线程安全的东西(synchronized)。
我把这个程序简化:
public class TT implements Runnable {
int b = 100;
public void run() {
b = 10000;
}
public static void main(String[] args) throws Exception {
TT tt = new TT();
Thread t = new Thread(tt);
t.start();
// Thread.sleep(1);(Uncomment this line if you have no patience to run)
System.out.println(tt.b);
}
}
如果你有足够的耐心,你会看到100和10000两种输出结果,当然,由于现在计算机速度,看到10000很难,所以,你可以打开注释的行来模拟线程的切换。
现在解释一下我简化的程序:我们有两个线程,一个主线程,他的代码主体在main函数里面,一个我们声明的线程,他的代码在run函数里面,程序开始运行从main入口进入,到t.start()之后,我们声明的线程也准备好了,这个时候便有了两个线程,大家都想要cpu,现在就走到了一个