这段代码不是违反了临界区的互斥吗?
Is not this code violating mutual exclusion in critical section?
我是 Java 的新手,正在尝试了解 Java 中的并发性。在探索时,我在 Java 并发性上非常流行 page 上遇到了这段代码:
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;
}
保存在同步块之外,因此如果某个线程在 add() 或 next() 中修改同步块内的 linkedSites,则允许其他线程读取它。
如有错误请指正
严格意义上的互斥你是对的。但即使在多线程程序中,当您访问例如阅读。我不知道整个程序,但 next()
可能会被调用几次。如果线程错过了某个条目,其他条目可能会在稍后捕获它。但是,正如您所说,不能保证其他人会看到更改。
linkedSites.size() 应该在同步块内,否则它可能看不到其他线程对 linkedSites 所做的更改。
你是对的 - 我认为代码作者可能认为他们在做一些聪明的事情,通过在进入同步部分之前检查 linkedSites 数组不为空来节省一点时间。这可能看起来很安全,因为在同步部分内再次检查了大小。
但是,Java 内存模型不能保证调用 next() 的线程将看到 linkedSites 与最后一个修改它的线程处于相同状态,除非读取也在同步部分中完成,因此理论上,尽管另一个线程已将数据放入其中,但调用 next 的线程可能会继续将数组视为空。每个线程都可能拥有自己的对象数据副本,该副本仅通过同步代码块与其他线程的副本同步。因此,接下来调用的线程可能会错误地将数组视为空数组。
我是 Java 的新手,正在尝试了解 Java 中的并发性。在探索时,我在 Java 并发性上非常流行 page 上遇到了这段代码:
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;
}
保存在同步块之外,因此如果某个线程在 add() 或 next() 中修改同步块内的 linkedSites,则允许其他线程读取它。
如有错误请指正
严格意义上的互斥你是对的。但即使在多线程程序中,当您访问例如阅读。我不知道整个程序,但 next()
可能会被调用几次。如果线程错过了某个条目,其他条目可能会在稍后捕获它。但是,正如您所说,不能保证其他人会看到更改。
linkedSites.size() 应该在同步块内,否则它可能看不到其他线程对 linkedSites 所做的更改。
你是对的 - 我认为代码作者可能认为他们在做一些聪明的事情,通过在进入同步部分之前检查 linkedSites 数组不为空来节省一点时间。这可能看起来很安全,因为在同步部分内再次检查了大小。
但是,Java 内存模型不能保证调用 next() 的线程将看到 linkedSites 与最后一个修改它的线程处于相同状态,除非读取也在同步部分中完成,因此理论上,尽管另一个线程已将数据放入其中,但调用 next 的线程可能会继续将数组视为空。每个线程都可能拥有自己的对象数据副本,该副本仅通过同步代码块与其他线程的副本同步。因此,接下来调用的线程可能会错误地将数组视为空数组。