同步方法无法正常工作

时间:2019-06-07 04:52:30

标签: java multithreading synchronized

嗨,我刚刚了解了多线程以及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完成?

1 个答案:

答案 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