最近在讀《Java併發編程實戰》這本書時,其中有一句話顯示: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
對象而言,它自身是無狀態的,也是線程安全的。 less
參考資料:dom