Java 同步和线程

标签 java multithreading

import java.util.Random;

public class ClassA{
  int a = 0, b = 10;
  Random rand = new Random();

  public synchronized void add(){
      if (a < 10){ 
         a++;
         b--;
      };
  }

  public synchronized void subtract(){
      if (b < 10){ 
         b++;
         a--;
      }
  }
  
  public synchronized boolean check(){
     return a + b == 10;
  }
  
  
  public static void main(String args[]){
      
      ClassA a = new ClassA();
      
      B ba = new B(a);
      B bb = new B(a);
      
       //notice these two threads are not associated with the object a!
      Thread t11 = new Thread(bb);
      Thread t22 = new Thread(ba);
      t11.start(); 
      t22.start();
  }
}


class B implements Runnable{
    ClassA a;
    
    B(ClassA a){
        this.a = a;
    }
   
    @Override
    public void run(){
        while (a.check()){
          if (a.rand.nextInt(2) == 1)
              a.subtract();
          else
              a.add();
      } System.out.print("Out of sync");
    }
}
我试图更好地理解java多线程。所以,我知道俗话说只有一个线程可以访问一个对象实例,从而调用该实例的方法(在这种情况下,例如 subtract 类中的 classA 方法。
但是,当您仍然拥有 classA 的相同实例时会发生什么? , a但是两个线程与不同的类 classB完全想调用a的方法?我希望消息 out of sync永远不会被打印出来,但确实如此。毕竟还是只有一个对象实例a ,这是否意味着同步不适用于此示例?

最佳答案

在您的情况下,out of sync永远不会被打印出来,因为对于您的情况,多线程是正确实现的:执行一系列操作并因此不是原子的关键方法通过使用 synchronized 的行为类似于原子方法。方法的关键字。
假设声明了一个代码块 synchronized (x) .
第一个进入这个代码块的线程获得对象x的锁并愉快地执行该代码块。
任何试图进入同一对象上的 block 的非第一个线程x通过将线程放入 x 的锁池中被“挂起” .一旦当前拥有锁的线程离开 synchronized (x) block ,来自锁池的随机线程成为执行该 block 的下一个线程。
使用 synchronized 时在实例方法上,它实际上与用 synchronized (this) 包装方法的全部内容相同。 . (对于 static 方法,它将是封闭类的类对象。)
因此,在您的情况下,有一个类的实例 A ,并且所有同步都发生在它上面。
如果你想看out of sync消息,请尝试删除 synchronized关键词。一段时间后,您应该会看到预期的 out of sync信息。
旁注:

  • 因为out of sync是一条消息,它可能应该打印在 System.err ,而不是 System.out .
  • 而不是 a.rand.nextInt(2) == 1 , 你可以使用 a.rand.nextBoolean() .
  • class B访问字段 randclass A打破封装,你可能想给 class A一种方法randomBoolean() return rand.nextBoolean() , 并调用该方法 randomBoolean()来自 class B .
  • 在不同的上下文中具有不同含义的相同变量名可能会令人困惑。在 class A , 变量 ab表示两个数字,在其他情况下,变量 ab引用 class A 的实例和 class B .考虑重命名 class A 的字段到别的东西,比如 number1number2 .
  • 关于Java 同步和线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63202516/

    相关文章:

    c# - Visual Studio 2015 调试在多线程应用程序中不起作用

    c# - ProgressChanged 回调上的 BackgroundWorker 和 UserState 问题

    java - 如何在 GWT 弹出面板中将焦点设置在 TextBox 上?

    java - 超越 .properties 的比较

    java - 可以单独访问的多个线程

    c# - 避免在后台任务仍在运行时处理DbContext的更优雅的解决方案

    java - 登录条件不起作用

    java gae谷歌云存储迭代存储桶中的文件

    java - jmeter 无法运行!无法找到 Java 可执行文件或版本。请检查您的 Java 安装”

    java - 线程快速排序