【问题标题】:Could you explain me one thing about synchronization in Java?你能解释一下关于Java同步的一件事吗?
【发布时间】:2017-11-29 18:21:20
【问题描述】:

假设我们有一个多线程应用程序和一个具有以下变量和方法的类:

private List list = new ArrayList();
public void doNothing() {
    synchronized (list) {
        list.get(0);
        String stuff = "Stuff";
        list.get(0);
    }
}

当一个线程处理方法 doNothing() 时,它会失去对 String stuff = "Stuff"; 的监控,并且 list.get(0); 的输出可能会有所不同,因为其他线程可以修改列表,我对吗?

【问题讨论】:

  • stuff 在您的示例中不受监控,list.get(0) 可能会或可能不会返回不同的值,具体取决于更新时修饰符是否在列表上同步。
  • 首先,这取决于锁定其他线程正在做什么(如果有)。
  • 没有。列表中的监视器一直保持到同步块结束。
  • ...String stuff 与其余代码有什么关系?联系真的不清楚。

标签: java multithreading synchronization


【解决方案1】:

是的,你是对的,但不是因为监视器在处理内容字符串时丢失了。您在列表上同步的事实不会阻止另一个线程对其进行更改。强制列表在两次获取之间保持不变的唯一方法是让所有更改列表的线程在同步(列表)中运行该代码。此外,Synchronized list 对您的情况也无济于事。

【讨论】:

    【解决方案2】:

    同步块中一次只能有一个线程工作。但是,如果任何其他线程在例如某个其他函数中修改列表,那么当然,list.get(0) 的输出在调用之间可能会有所不同。由于在此块中创建的字符串内容不能被任何其他线程更改,而不是当前正在运行的线程。

    【讨论】:

      【解决方案3】:

      只有一个线程可以在同一个监视器对象上同步的 Java 代码块内执行。

      线程只有在到达同步块的末尾时才会“丢失监视器”。

      在您的具体情况下,调用 list.get(0); 的结果;可以相同也可以不同,这取决于其他线程可以在列表对象上同步的任何代码块之外调用该列表上的修改器。

      同步对象的目的是允许你在同一个锁上同步多个块。

      在以下示例中,只有一个线程可以同时在两个块中的任何一个中执行:

      public void doNothing() {
          synchronized (list) {
              //someStuff
          }
      }
      
      public void doSomething() {
          synchronized (list) {
              //anotherStuff
          }
      }
      

      【讨论】:

      • 但是如果我写 synchronized(list) 是否意味着整个应用程序中只有 1 个线程可以访问这个列表?
      • 没有。这意味着只有一个线程可以在“列表”对象上同步的任何块内执行。如果您有许多代码块访问相同的敏感数据,您可以同步同一个对象上的所有代码块,允许只有一个线程可以同时在其中任何一个内执行
      • 我编辑了我的答案以解决同步对象的目的
      • 所以如果这两个方法在不同的类中,这意味着当某个线程执行 doNothing() 时其他线程不能执行 doSomething?
      • 是的,就是这个意思……只要它们在完全相同的对象上同步,就只有一个线程可以同时执行它们中的任何一个。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-25
      • 2011-08-31
      • 2022-11-24
      • 2010-09-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多