难道这段java代码的线程安全有什么问题吗?线程 1-10 通过 sample.add() 添加数字,线程 11-20 调用 removeAndDouble() 并将结果打印到标准输出。我回想起有人说过,在同步块(synchronized block)之外使用它的 removeAndDouble() 中使用它的方式分配项目可能不是线程安全的。编译器可能会优化指令,使它们乱序出现。这里是这样吗?我的 removeAndDouble() 方法不安全吗?
从并发的角度来看,这段代码还有什么问题吗?我正在尝试使用 Java(1.6 以上版本)更好地理解并发性和内存模型。
import java.util.*;
import java.util.concurrent.*;
public class Sample {
private final List<Integer> list = new ArrayList<Integer>();
public void add(Integer o) {
synchronized (list) {
list.add(o);
list.notify();
}
}
public void waitUntilEmpty() {
synchronized (list) {
while (!list.isEmpty()) {
try {
list.wait(10000);
} catch (InterruptedException ex) { }
}
}
}
public void waitUntilNotEmpty() {
synchronized (list) {
while (list.isEmpty()) {
try {
list.wait(10000);
} catch (InterruptedException ex) { }
}
}
}
public Integer removeAndDouble() {
// item declared outside synchronized block
Integer item;
synchronized (list) {
waitUntilNotEmpty();
item = list.remove(0);
}
// Would this ever be anything but that from list.remove(0)?
return Integer.valueOf(item.intValue() * 2);
}
public static void main(String[] args) {
final Sample sample = new Sample();
for (int i = 0; i < 10; i++) {
Thread t = new Thread() {
public void run() {
while (true) {
System.out.println(getName()+" Found: " + sample.removeAndDouble());
}
}
};
t.setName("Consumer-"+i);
t.setDaemon(true);
t.start();
}
final ExecutorService producers = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
final int j = i * 10000;
Thread t = new Thread() {
public void run() {
for (int c = 0; c < 1000; c++) {
sample.add(j + c);
}
}
};
t.setName("Producer-"+i);
t.setDaemon(false);
producers.execute(t);
}
producers.shutdown();
try {
producers.awaitTermination(600, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
sample.waitUntilEmpty();
System.out.println("Done.");
}
}
最佳答案
对我来说它看起来是线程安全的。这是我的推理。
每次访问 list
都是同步的。这很棒。即使您在 item
中提取了 list
的一部分,该 item
也不会被多个线程访问。
只要您只在同步时访问 list
,就应该很好(在您当前的设计中。)
关于java - 将对象分配给在同步块(synchronized block)外定义的字段 - 它是线程安全的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3781694/