最近在读《Java并发编程实战》这本书时,其中有一句话显示:
无状态对象一定是线程安全的
当时就产生了怀疑,写一段代码举例:
public class ListDemo {
public List<Integer> nums = Lists.newArrayList(1, 2, 3);
@Override
public String toString() {
return "nums=" + nums;
}
}
public class FakeStateless {
public void modifyList(ListDemo listDemo) {
listDemo.nums.add(LocalTime.now().getNano());
System.out.println(this.getClass().getName() + listDemo);
}
}
public class App {
public static Random random = new Random();
public static void main(String[] args) throws InterruptedException {
ListDemo listDemo = new ListDemo();
FakeStateless A = new FakeStateless();
FakeStateless B = new FakeStateless();
new Thread(() -> {
sleepRandomTime();
A.modifyList(listDemo); // nums=[1, 2, 3, 918000000]
}).start();
new Thread(() -> {
sleepRandomTime();
B.modifyList(listDemo); // nums=[1, 2, 3, 918000000, 680000000]
}).start();
Thread.sleep(2000);
System.out.println("main" + listDemo); // nums=[1, 2, 3, 918000000, 680000000]
}
private static void sleepRandomTime() {
try {
Thread.sleep(random.nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
然后说:看!ListDemo listDemo根本就不线程安全。但真的是这样吗?《Effective Java》和《Java并发编程实战》两本书的作者有必要骗人吗?
我们再回来看看无状态的定义:
Stateless object is an instance of a class without instance fields (instance variables). The class may have fields, but they are compile-time constants (static final).
// 无状态对象是没有实例字段(实例变量)的类的实例。该类可能具有字段,但是它们是编译时常量(静态final)。
等下!我们这里说的无状态对象是FakeStateless这个对象,不是它操作的ListDemo listDemo. 现在看来,是无状态对象FakeStateless的一个方法modifyList在操作一个不属于自己实例变量的有状态对象ListDemo listDemo。 modifyList方法的调用并没有改变FakeStateless这个对象本身的状态。所以对FakeStateless对象而言,它自身是无状态的,也是线程安全的。
参考资料: