無狀態與線程安全

最近在讀《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 listDemomodifyList方法的調用並無改變FakeStateless這個對象自己的狀態。因此對FakeStateless對象而言,它自身是無狀態的,也是線程安全的。 less

參考資料:dom

相關文章
相關標籤/搜索