java - 这段代码是不是违反了临界区的互斥?

标签 java multithreading concurrency synchronized synchronized-block

我是 Java 新手,正在尝试了解 Java 中的并发性。在探索时,我在相当流行的 page 上发现了这段代码。关于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;
    }
  }

}

我认为这里的函数 next() 违反了互斥,如下所示:

if (linkedSites.size() == 0) {
  return null;
}

保留在同步块(synchronized block)之外,因此如果某个线程正在 add() 或 next() 中的同步块(synchronized block)内修改 linkedSites,则允许其他线程读取它。

如有错误,请指正。

最佳答案

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

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

关于java - 这段代码是不是违反了临界区的互斥?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27840116/

相关文章:

java - 安卓数学游戏 : How to get only non-negative subtraction questions and whole numbers only for division?

Java - 为什么我在 JFrame 中看不到我的列表?

java - 迭代同步块(synchronized block)中检索的列表是线程安全的吗?

java - 访问静态字段的静态同步方法

Java-并发修改异常

java - 删除 ArrayList 中的重复数组?

java - 在 Java 中嵌入 Office

java - 从 ThreadPoolTask​​Executor 获取可调用或将 Runnable 转换为 Callable

multithreading - 按线程排序

wcf - NHibernate和WCF : Performance (session reuse) vs.并发(同时请求)