返回信息流源码如下:
public class TestThread implements Runnable{
int b =100 ;
public synchronized void m1() throws InterruptedException{
b=1000;
Thread.sleep(5000);
System.out.println("m1(): b="+b);
}
public synchronized void m2() throws InterruptedException{
Thread.sleep(2500);
System.out.println("-------------");
b=2000;
}
@Override
public void run() {
// TODO Auto-generated method stub
try{
m1();
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
TestThread tr = new TestThread();
Thread tt = new Thread(tr);
tt.start();
tr.m2();
System.out.println("主线程 : b="+tr.b);
// Thread.sleep(1000);
// System.out.println("主线程 : b="+tr.b);
Thread.sleep(10000);
System.out.println("最后结果 : b="+tr.b);
}
}
运行结果:
-------------
主线程 : b=1000
m1(): b=1000
最后结果 : b=1000
这里不明白的是, synchronized的作用不是不同线程只能在同一个对象上加一把锁么?既然一个对象只能有一把锁的话, 那用两个synchronized方法同步访问还是有问题,还不如直接把对象给锁住呢。。。
这是一条镜像帖。来源:北邮人论坛 / java / #13245同步于 2010/2/9
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖
[求助]关于多线程的运行结果, 请教大牛们
lblz
2010/2/9镜像同步9 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
我每一次的执行不确定,有可能是
-------------
主线程 : b=2000
m1(): b=1000
最后结果 : b=1000
跟你的不一样。
关键在于到底是主线程还是子线程先得到执行权限。
synchronized 方法的意思是,在执行这个方法期间,别的thread不能得到锁。
但是具体哪个thread能够竞争到最先的那个执行权,还是不确定的。
注意main方法中的这两句
tt.start();
tr.m2();
其中tt.start()执行后会调用run方法,但start方法是即刻返回的,也就是说不等run方法执行与否就会返回,进而执行tr.m2()。这时是不能判断run方法和tr.m2()哪个先执行。因为这是两个线程,地位是平等的。 理解这个是重点。
另外synchronized不管几个方法用,都是锁定该对象。 所以不会出现你所说的两个方法同时访问的情况。你多运行几次,会发现结果会有不同。
【 在 greedisgood 的大作中提到: 】
: 注意main方法中的这两句
: tt.start();
: tr.m2();
: ...................
这里的锁定该对象,指的是TestThread类的对象吧, 那按照这样理解的话,出现这样的结果:
-------------
主线程 : b=1000
m1(): b=1000
最后结果 : b=1000
那分析下执行的顺序:
1. 先是主线程m2()方法执行完"------------------"并将b值由100改为2000,然后时间片结束。
2. 执行线程2的m1()方法将b值由2000改为1000, 然后回到主线程。
3. 执行主线程的 System.out.println("主线程 : b="+tr.b), 得到 主线程 : b=1000
4. 然后继续执行线程2的m1()方法, 打印 m1(): b=1000
5. 最后执行主线程,打印 最后结果 : b=1000
应该是这样的执行结果, 但是我有一个疑问, 这样由CPU进行线程间的切换的话, 由于m1()和m2()方法都加了锁,那这两个方法在执行的时候tr这个对象应该是被锁住了啊, 既然是锁住的话,那么如果CPU从一个线程对象切换到另外一个线程对象,用的是同一个TestThread对象, 难道不会重复的加锁么? 比如从主线程的m2()切换到线程2的m1(), 那主线程的m2()加在tr上的锁怎么办? 请指教.
不明白你的意思。首先你的程序可以得到随机的结果,可以是
-------------
主线程 : b=2000
m1(): b=1000
最后结果 : b=1000
或者
-------------
主线程 : b=1000
m1(): b=1000
最后结果 : b=1000
说明你的测试程序有问题,你的执行结果是取决于lucky time的,你的同步策略失败了。为什么失败了,因为你没有封装。
int b =100 ;
System.out.println("主线程 : b="+tr.b);
println方法在执行的过程中main线程不需要得到对象tr的锁就可以得到这个值,没有同步策略的保证,你在main线程里得到的值可能是stale value,换句话说你在线程Thread tt = new Thread(tr)中用m1更改的b=1000可能对main线程来说是不可见的,也就是说这个值可能是由编译器优化了执行策略,把这个更改值暂时存在寄存器或者缓存里,而不是内存里面,所以对不起我的main线程可能看不见这个值了。main线程可能还只能看见我的值b=2000,可能过段时间后我的tt线程把b=1000这个值更新到内存中时我的main线程又看见的是1000了,在这个过程中tt线程看见的始终是b=1000。这就是多线程里一个很重要而又容易被忽视的原则visibility,共享的始终是内存堆对象,不是寄存器,缓存,方法栈,而编译器为了提高效率有的更新值不是直接写入内存里的。
你破坏了封装性,不管线程tt是否持有对象tr锁,你的main线程任何时候都可能得到b值。
一个加了锁后 其它的访问会排队 不会重复加锁
【 在 lblz 的大作中提到: 】
:
: 【 在 greedisgood 的大作中提到: 】
: : 注意main方法中的这两句
: ...................
【 在 lblz 的大作中提到: 】
: [color=#FF4500]这里的锁定该对象,指的是TestThread类的对象吧, 那按照这样理解的话,出现这样的结果:
: -------------
: 主线程 : b=1000
: ...................
你分析的执行顺序是错的。
多看看线程的基础吧,特别是并发那一块。
注意你的第1至5步,看着俩线程交替进行貌似很人道,其实根本不是那么回事。
注意你的变量域b并没有加锁啊。。对非同步的变量访问不会产生线程序列化的效果。