【问题标题】:Synchronized method isn't working as i expected同步方法没有按我预期的那样工作
【发布时间】:2019-06-07 04:52:30
【问题描述】:

您好,我刚刚了解了多线程以及同步在 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”同时出现,我不知道为什么。如果 synchronized 一次只允许 1 个线程,那么 z 是否应该被困在 enterQ() 直到 y 完成?

【问题讨论】:

  • testMulti.enterQ() 方法在当前实例上同步,你有三个独立的实例。
  • 我怀疑它是输出。请粘贴您的确切代码。在您的主要功能中,您正在更改同一对象的任务名称,因此它会多次打印相同的字母
  • @Rumd 除非他将manageThread.obj 声明为transient,否则此输出是您所期望的。
  • FWIW:看起来您好像在使用iBusy 来创建自己的锁定机制,但synchronized 锁定机制...
  • 另外,您的run() 方法似乎只做一件事,并且一直保持锁定状态。也就是说,您正在尝试创建三个线程,每个线程一次做一件事情。这违背了线程的全部目的,即允许不同的线程在同时时间做他们的事情。

标签: java multithreading synchronized


【解决方案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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-16
    • 1970-01-01
    • 2016-06-19
    • 2013-04-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多