我是 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/