我对Concurrency很陌生,但此刻得到了这个要点;我有一个 NOT Thread Safe 的程序,因此可能会破坏类的主要下限小于等于上限的不变量。 我想出了一个主要的方法,希望它在真实时打印出来,但是无法理解为什么它不会。
public class Conc implements Runnable {
// Invariant: lower <= upper
private final AtomicInteger lower = new AtomicInteger(0);
private final AtomicInteger upper = new AtomicInteger(0);
public void setLower(int l) {
if (l <= upper.get())
lower.set(l);
}
public void setUpper(int u) {
if (u >= lower.get())
upper.set(u);
}
public boolean isInRange(int i) {
return (i >= lower.get() && i <= upper.get());
}
public boolean invariantSatisfied() {
return (lower.get() <= upper.get());
}
public static void main(String[] args) {
Thread t1 = new Thread(new Conc());
Thread t2 = new Thread(new Conc());
Thread t3 = new Thread(new Conc());
t1.start();
t2.start();
t3.start();
}
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
setUpper(i - 10000);
setLower(i + 800000);
if (invariantSatisfied() == false) {
System.out.println("False");
}
System.out.println();
}
}
}
答案 0 :(得分:1)
此程序存在一些导致意外结果的问题。
首先指出的是代码实际上是线程安全的。 这是因为每个Object都有它自己引用的字段集,每个线程都有自己的对象。
这可以通过几种方式解决
你可以在每个线程中使用相同的对象
Conc target = new Conc ();
Thread t1 = new Thread(target);
Thread t2 = new Thread(target);
Thread t3 = new Thread(target);
t1.start();
t2.start();
t3.start();
或者您可以将字段设为静态,这意味着只有一个实例
private static final AtomicInteger lower = new AtomicInteger(0);
private static final AtomicInteger upper = new AtomicInteger(0);
你遇到的另一个问题是,即使这个程序不是线程安全的,测试失败的窗口也很小,因为输入数据很少会失败。
for(int i = 0; i < 1000000; i++){
setUpper(i);
setLower(i);
if(!invariantSatisfied()){
System.out.println("False");
}
}
解决了这个问题。
答案 1 :(得分:0)
当您创建线程时,为每个线程提供Conc
类的新实例。这意味着可以同时访问lower
和upper
个实例变量,每个线程都有自己的变量。
所以这里没有并发问题,更像是算法的问题。
代码是线程安全的。