日期:2014-05-20  浏览次数:20628 次

还是关于java多线程的问题
有如下一段代码,
public class TT implements Runnable {
int b = 100;

public void m1() throws Exception{
//public synchronized void m1() throws Exception{ //***************************************

b = 1000;
Thread.sleep(5000);
System.out.println("b = " + b);
}

public synchronized void m2() throws Exception {
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);
}
}
在当前代码下,运行的结果是
2000
b=2000,可是如果把其中一行代码换成注释的那一行,也就是加上Synchornized,结果变为
1000
b=1000,学习视频上的一个例子,虽然有解释但我总觉得没听的很明白,求高手分析一下啊,还有最好能帮忙解释一下用Synchornized锁定一个方法会有什么效果。特点之类的,拜谢了。

------解决方案--------------------
你这两种情况下执行的结果都是不确定性的

你有两个线程,两个线程的执行是交错执行(即使是并行的,也可以按交错的思维来思考)的,所谓交错就是线程t执行一条或几条语句,主线程执行一条或几条语句,按照这个思路分析,碰到两个线程同时获取锁时必然有一个成功获得锁并继续执行,另外一个线程只能等待
------解决方案--------------------
因为当把m2执行后程序并没有执行System.out.println(tt.b);
而是转向t.start();所以是1000,1000。

------解决方案--------------------
第一种情况好理解:
程序运行到t.start()时,又启动了一个线程,t这个新线程要经过从“就绪状态”等待虚拟机调度到“运行状态",所以一般情况下慢于主线程main(),这时tt.m2()(在主线程)继续执行,进入m2方法,先休眠2.5秒。在主线程进入休眠的时候,t线程就会被调度运行,给变量b赋值1000后,这个线程也休眠了。因为他要休眠5秒,所以在大约2.4秒后,主线程结束休眠,给b赋值2000。所以最后b值为2000。
注意:在这种情况下,m2()方法加的同步没有任何意义。没有其他线程需要那个同步对象,执行同步方法。

第二种情况就不一样了。
给方法m1()也加了同步,使用的同步对象都是tt. 运行带同步的方法必需那个同步对象的锁空闲时才能运行,否则在阻赛状态等待。
开始运行的情况和第一种情况一样,tt.m2()先运行,它马上休眠2.5毫秒,但这时和第一种情况不同,t线程虽启动,但m1方法无法运行,(这就是synchronized 的作用),必须等主线程m2()执行完才能运行。 所以m2()休眠结束继续执行,b=2000. 并释放同步对象的锁并继续运行。
这时m1()得到了锁,从阻塞状态进入就绪状态,虚拟机会调度它进入运行状态。因为它第一条语句就是个赋值语句,所以一般它比主线程的那句System.out.println(tt.b);要快,(就是说虽然b先被赋值2000,但没等这条语句执行完,t线程进入运行状态,把b赋值成1000了。 最后输出1000。

楼主可以在几个地方加点语句,试试运行结果。

1 在t.start()后,休眠几毫秒。
2 在方法m1() b=1000;之前,随便加一条System.out.println("xxx");语句。


------解决方案--------------------
锁定函数,相当与this。锁定代码块,相当与类名的字节码文件,在你加锁的时候由于共享同一资源,所以你必须保证一致性!