Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 本规范是否违反了关键部分的互斥?_Java_Multithreading_Concurrency_Synchronized_Synchronized Block - Fatal编程技术网

Java 本规范是否违反了关键部分的互斥?

Java 本规范是否违反了关键部分的互斥?,java,multithreading,concurrency,synchronized,synchronized-block,Java,Multithreading,Concurrency,Synchronized,Synchronized Block,我是Java新手,正在努力理解Java中的并发性。在探索过程中,我在一个非常流行的Java并发上遇到了以下代码: public class CrawledSites { private List<String> crawledSites = new ArrayList<String>(); private List<String> linkedSites = new ArrayList<String>(); public void a

我是Java新手,正在努力理解Java中的并发性。在探索过程中,我在一个非常流行的Java并发上遇到了以下代码:

public class CrawledSites {
  private List<String> crawledSites = new ArrayList<String>();
  private List<String> linkedSites = new ArrayList<String>();

  public void add(String site) {
    synchronized (this) {
      if (!crawledSites.contains(site)) {
        linkedSites.add(site);
      }
    }
  }


/**
   * Get next site to crawl. Can return null (if nothing to crawl)
   */

  public String next() {
    if (linkedSites.size() == 0) {
      return null;
    }
    synchronized (this) {
      // Need to check again if size has changed
      if (linkedSites.size() > 0) {
        String s = linkedSites.get(0);
        linkedSites.remove(0);
        crawledSites.add(s);
        return s;
      }
      return null;
    }
  }

}
保持在同步块之外,因此,如果某些线程在add()或next()中修改同步块内的linkedSites,则允许其他线程读取它


如果我错了,请纠正我。

严格意义上的互斥,你是对的。但是,即使在多线程程序中,当您访问(例如用于阅读)时,也没有必要将所有数据同步。我不知道整个程序,但是
next()
可能会被调用几次。如果线程错过了某个条目,可能其他线程稍后会捕获它。但是,正如您所说,不能保证其他线程会看到更改。

linkedSites.size()应该在同步块中,否则它可能看不到其他线程对linkedSites所做的更改

你是对的-我认为代码作者可能认为他们做了一些聪明的事情,在进入同步部分之前检查linkedSites数组是否为空,从而节省了一点时间。这看起来很安全,因为在同步部分中再次检查了大小


但是,Java内存模型不能保证调用next()的线程将看到与最后一个修改它的线程处于相同状态的linkedSites,除非读取也在同步部分中完成,因此理论上,调用next()的线程可能会继续看到数组为空,尽管另一个线程已将数据放入其中。每个线程都可能有自己的对象数据副本,该副本只能通过同步代码块与其他线程的副本同步。因此,调用next的线程可能会错误地将数组视为空。

您没有错。对列表的每次访问都应同步。
if (linkedSites.size() == 0) {
  return null;
}