嗨,我刚刚了解了多线程以及Java中同步的工作原理,所以我尝试对其进行测试。
所以我有这个课:
public class testMulti extends Thread{
manageThread obj; //has 2 fields, boolean flag and task name
testMulti(manageThread obj){
this.obj = obj;
}
public void run() {
switch(obj.taskName) {
case "x" :
while(true){
enterQ();
obj.doX() // print "x" and sleep for 5 secs
obj.iBusy = false;
}
case "y" :
while(true){
enterQ();
obj.doX() // print "y" and sleep for 5 secs
obj.iBusy = false;
}
case "z" :
while(true){
enterQ();
obj.doX() // print "z" and sleep for 5 secs
obj.iBusy = false;
}
}
}
synchronized public void enterQ(){
while(true) {
if(!obj.iBusy) {
obj.iBusy = true;
return;
}
}
}
}
我也有这个单独的主体:
public static void main(String[] args) {
manageThread obj = new manageThread();
obj.taskName = "x";
testMulti test1 = new testMulti(obj);
test2.start();
obj.taskName = "y";
testMulti test2 = new testMulti(obj);
test2.start();
obj.taskName = "z";
testMulti test3 = new testMulti(obj);
test3.start();
}
在打印“ x”后我有5秒钟的延迟,但是“ y”和“ z”同时出现,我不知道为什么。如果同步一次只允许一个线程,那么z是否应该一直停留在enterQ()
中,直到y完成?
答案 0 :(得分:1)
正如@ user207421在其评论中提到的,您正在使用testMulti
类的三个单独的实例,因此在三个不同的锁上进行同步。请参见JLS中的synchronized Methods:
同步方法在执行之前先获取一个监视器(第17.1节)。
对于类(静态)方法,与该类关联的监视器 该方法的类的对象。
最简单(但并非完全正确的解决方案)是在testMulti.obj
上进行同步,而不是在enterQ
方法上进行同步:
public void enterQ(){
synchronized(obj) {
while(true) {
if(!obj.iBusy) {
obj.iBusy = true;
return;
}
}
}
}
这不是完全正确的,因为obj.iBusy = false
是从非同步上下文中调用的,这不能保证其他线程可以看到更改。有关所有血腥细节,请参见Java Memory Model。