阅读《java并发编程实战》第三章
阅读《java并发编程实战》第三章
第一个例子,没有重现
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while (!ready) {
Thread.yield();
}
System.out.println(number);
}
}
public static void main(String[] args) throws InterruptedException {
new ReaderThread().start();
// 加入睡眠让子线程启动好,也无法重现
// Thread.sleep(1000);
number = 42;
ready = true;
}
}
// 结果:
// 程序能正常结束,输出42。没有展示出可见性的问题。
例子:可变正数类
@NotThreadSafe
class MutableInteger {
private int value;
public int get() { return value; }
public void set(int value) { this.value = value; }
}
// 通过添加synchronized锁,对get/set都要加
@ThreadSafe
class MutableInteger {
private int value;
public synchronized int get() { return value; }
public synchronized void set(int value) { this.value = value; }
}
要点:加锁(内置锁或Lock)能保证可见性。当线程B执行由锁保护的同步代码块时,可以看到线程A之前在同一个同步代码块中的所有操作结果。【加锁的含义不仅仅局限于互斥行为,还包括内存的可见性】
要点2:volatile变量,是java语言提供的一个稍弱的同步机制,确保变量的更新操作通知到其他线程。
从内存可见性角度来看,写入volatile变量相当于退出同步代码块,而读取volatile变量就相当于进入同步代码块。
要点3:发布(publish)一个对象是指,使对象能在当前作用域之外的代码中使用。例如:将一个对象引用保存到其他代码可以访问的地方;或者在某个非私有得方法中返回该引用;或者将引用传递到其他类的方法中。
// 发布对象举例
class UnsafeStates {
private String[] states = {"AK", "AL"};
public String[] getStates() {
return states;
}
}
class Demo {
public static Set<Secret> knownSecrets;
public void initialize() {
knownSecrets = new HashSet<Secret>();
}
}
3-12, 3-13:
@Immutable
class OneValueCache {
private final BigInteger lastNumber;
private final BigInteger[] lastFactors;
public OneValueCache(BigInteger lastNumber, BigInteger[] lastFactors) {
this.lastNumber = lastNumber;
// 有问题,没有对lastFactors做null判断
this.lastFactors = Arrays.copyOf(lastFactors, lastFactors.length);
}
public BigInteger[] getFactors(BigInteger i) {
if (lastNumber == null || !lastNumber.equals(i)) {
return null;
}
return Arrays.copyOf(lastFactors, lastFactors.length);
}
}
@ThreadSafe
class VolatileCachedFactorizer implements Servlet {
private volatile OneValueCache cache = new OneValueCache(null, null);
public void sevice(ServletRequest req, ServletResponse resp) {
BigInteger i = extractFromRequest(req);
BigInteger[] factors = cache.getFactors(i);
if (factors == null) {
factors = factor(i);
cache = new OneValueCache(i, factors);
}
encodeIntoResponse(resp, factors);
}
}