java - 同步方法没有像我预期的那样工作

标签 java multithreading synchronized

您好,我刚刚了解了多线程以及同步在 Java 中的工作原理,所以我尝试对其进行测试。
所以我有这个类(class):

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 完成?

最佳答案

正如@user207421 在他的评论中提到的,您正在使用 testMulti 类的三个独立实例,因此在三个不同的锁上进行同步。参见 synchronized Methods在 JLS 中:

A synchronized method acquires a monitor (§17.1) before it executes.

For a class (static) method, the monitor associated with the Class object for the method's class is used.

最简单(但不是完全正确的修复)是在 testMulti.obj 而不是 enterQ 方法上同步:

public void enterQ(){
    synchronized(obj) {
        while(true) {
            if(!obj.iBusy) {
                obj.iBusy = true;
                return;
            }
        }
    }  
}

这并不完全正确,因为 obj.iBusy = false 是从非同步上下文中调用的,这不能保证其他线程可以看到更改。查看Java Memory Model对于所有血腥的细节。

关于java - 同步方法没有像我预期的那样工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56488131/

相关文章:

java - 是否真的有必要使用 "monitor"对象 (java)

java - 如何在函数式接口(interface)和方法引用上下文中的函数之间解释参数和自变量

java - 无论我做什么,Eclipse SVN 总是包含自动生成的 bin 目录和类

java - WeakHashMap<Integer, Vector<IConsumer>>,如果仅强引用IConsumers,Vector会被收集吗?

c - 在不创建新线程的情况下将调试器附加到进程

java - 如何使用 Eclipse 在 Java 中的同一监视器上找到所有同步的内容?

java - 如何使用 JDBC 工具访问 hsqldb 数据库?

java - Maven cargo : Could not find JNDI datasource

java - 在 GUI 中与 JavaFX 网络服务交互

Java happend-before 在同步块(synchronized block)中