public class TT implements Runnable {
int b = 100;
public synchronized void m1() throws Exception{
//Thread.sleep(2000);
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);
}
}
结果是:
1000
b = 1000
为什么顺序是m2()---m1() 执行m1()的时候打印tt.b 而不是在执行m2()的时候就打印?
int b = 100;
public synchronized void m1() throws Exception{
//Thread.sleep(2000);
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);
}
}
结果是:
1000
b = 1000
为什么顺序是m2()---m1() 执行m1()的时候打印tt.b 而不是在执行m2()的时候就打印?
public class TT implements Runnable {
int b = 100;
public synchronized void m1() throws Exception{
//Thread.sleep(2000);
b = 1000;
Thread.sleep(500);
System.out.println("b = " + b);
} public synchronized void m2() throws Exception {
Thread.sleep(250);
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();//线程t启动,执行run(),执行m1(),b=1000,开始睡5000
tt.m2();//同时主线程启动,执行m2(),睡2500,醒了以后b=2000,此时线程t还在睡着,主线程接着往下执行
System.out.println(tt.b);//主线程打印输出,此时的b是2000。
//5000以后线程t睡醒了,打印输出 b = 2000
}
}
按照正常的分析,似乎应该是注释当中的情形,但是实际上很不幸,根本不是!
多次执行上面的程序你就会发现,输出结果可能是:
1000
b = 1000
也可能是:
2000
b = 1000
原因是什么呢?这与java的内存模型有关系。1.java的内存模型分为主存储器与工作存储器两种:
(1)主存储器就是实例位置所在的区域,所有的实例都存在于主存储器内,
尤其是,实例所拥有的字段即位于主存储器内的区域,主存储器被所有的线程所共有。
(2)工作存储器是各个线程所拥有的作业区,所有的线程都有自己专有的工作存储器,
在工作存储器以内存在主存储器的必要部分的拷贝,称之为工作拷贝。
2.字段(field)的引用
线程无法对主存储器进行直接的操作,因此无法直接引用字段的值。
当线程要引用字段的值的时候,会一次将值从主存储器拷贝到工作存储器上,拷贝完成以后,线程就可以引用工作存储器里里面的值了。
当同一个线程再次引用这个值的时候,它有可能还是从主存储器拷贝以后在引用,也可能使用自己以前拷贝过来的值,这取决于jvm。
3.字段(field)的修改
线程无法对主存储器进行直接的操作,因此无法直接修改字段的值。
当线程要把值指定给字段的时候,会一次将值指定给工作存储器上的工作拷贝。指定完成以后,工作拷贝的内容便会影像到主存储器,至于合适会影像到主存储器取决于jvm。
当同一个线程反复修改同一个字段的时候,会发生什么情况?有可能只是反复的修改工作拷贝,最后的结果影像到主存储器,也可能每次修改以后都拷贝到主存储器,这取决于jvm。参考:[code=HTML]<a href="http://user.qzone.qq.com/605162215/infocenter?ptlang=2052&ADUIN=605162215&ADSESSION=1274251834&ADTAG=CLIENT.QQ.2587_Mysrv.0">http://user.qzone.qq.com/605162215/infocenter?ptlang=2052&ADUIN=605162215&ADSESSION=1274251834&ADTAG=CLIENT.QQ.2587_Mysrv.0</a>
[/code]
public synchronized void m1()
public synchronized void m2()
是2个同步块,互相之间没关系的。
//上次没看到那个synchronized,你看看这样解释可以吗?
public class TT implements Runnable {
int b = 100;
public synchronized void m1() throws Exception{
//Thread.sleep(2000);
b = 1000;
Thread.sleep(500);
System.out.println("b = " + b);
} public synchronized void m2() throws Exception {
Thread.sleep(250);
b = 2000;
}
public void run() {
try {
m1();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
long start=System.currentTimeMillis(); //1
TT tt = new TT(); //2
Thread t = new Thread(tt); //3 t.start();//4 线程t启动,但不一定立即就获得cpu,立即执行run()方法
tt.m2();//5 如果是主线程首先执行的话,执行m2(),此时线程t因为没有锁,被迫等待,
//主线程睡2500,醒了以后b=2000。
//退出m2()方法,释放锁,此时,等待的线程t获得锁,得以执行,主线程同时也继续执行。
System.out.println(tt.b);//主线程打印输出,b已经被主线程改为了2000,很有可能此时被t线程改为了1000,也可能没改,取决于谁先执行
t.join();//等待线程t结束
long end=System.currentTimeMillis();
System.out.println("耗时:"+(end - start));//输出:耗时:750
//如果去掉synchronized,输出耗时:500,说明两个方法m1和m2的确是互斥的。
}
}
//如果在第4行,t线程首先执行,主线程被迫等待,t执行完毕,b=1000,主线程继续往下执行。
问题是你调用start的时候只是调度了一个新线程,而这个线程并不是立即调用m1方法。而是根据CPU分配,有可能分配到主线程运行m2方法了
int b = 100; public synchronized void m1() throws Exception{
//Thread.sleep(2000);
System.out.println("m1() called");
b = 1000;
Thread.sleep(5000);
System.out.println("b = " + b);
} public synchronized void m2() throws Exception {
System.out.println("m2() called");
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);
}
}运行结果:
m2() called
2000
m1() called
b = 1000或者m2() called
m1() called
2000
b = 1000为什么每次都是 m2() called 先执行呢?