[英]Can a class with getters separate from input processing methods be considered “thread-safe”?
我正在讀一本關於Java的書,有一個練習題,他們用一個私有變量聲明了一個類,一個公共void
方法做了一些昂貴的操作來計算然后設置私有變量,另一個公共方法返回私人變量。 問題是“如何使這個線程安全”,一個可能的答案是“同步兩個方法中的每一個”,另一個可能的答案是“這個類不能成為線程安全的”。
我認為類不能成為線程安全的,因為即使你同步這兩個方法,你可能會遇到Thread1會調用setter的情況,在Thread1可以調用getter之前,Thread2可能會執行並調用setter,這樣當Thread1去檢索結果會得到錯誤的信息。 這是看待事物的正確方法嗎? 書中提出的正確答案是,通過同步這兩種方法可以使類成為線程安全,現在我很困惑......
我認為類不能成為線程安全的,因為即使你同步這兩個方法,你可能會遇到Thread1會調用setter的情況,在Thread1可以調用getter之前,Thread2可能會執行並調用setter,這樣當Thread1去檢索結果會得到錯誤的信息。 這是看待事物的正確方法嗎?
你是對的。 無法保證線程不會在類中調用每個方法之間調用任何一種方法。
如果你想這樣做,那將需要一個包裝類。 所以如果帶有getter和setter的類是這樣的:
class Foo
{
private static int bar;
public static synchronized void SetBar(int z) { ... }
public static synchronized int GetBar() { ... }
}
包裝類看起來像這樣:
class FooWrapper
{
public synchronized int SetGetBar(int z)
{
Foo.SetBar(z);
return Foo.GetBar();
}
}
保證這一點的唯一方法是,如果你可以保證所有的調用都將通過你的包裝類,而不是直接到類Foo。
當你使這兩個同步時,getter和setter本身是線程安全的。 進一步來說:
但是,使getter和setter 本身是線程安全的並不意味着應用程序作為一個整體 (即使用此類的任何東西)是線程安全的。 如果您的線程想要調用setter,那么在調用getter時獲取相同的值,這涉及在不同級別上的同步。
就線程安全性而言,線程安全類不需要控制如何調用其方法(例如,它不需要控制線程交換其調用的方式),但它需要確保它們何時 ,方法做他們應該做的事。
Java中的synchronized
是一個對象范圍的鎖。 任何給定對象的一個synchronized
方法一次只能在任何給定的線程上執行。 讓我們來上課:
class Foo
{
private int bar;
public synchronized void SetBar() { ... }
public synchronized int GetBar() { ... }
}
SetBar()
。 線程1獲取對象鎖。 SetBar()
,但線程1持有鎖。 線程2現在排隊等待線程1將釋放它時獲取鎖定。 SetBar()
並釋放鎖。 SetBar()
。 GetBar()
。 線程1現在排隊等待線程2將釋放它時獲取鎖定。 SetBar()
並釋放鎖。 GetBar()
,並完成它。 你做了兩次工作,但沒有造成任何競爭條件。 兩次工作可能會或可能不會是錯誤的,具體取決於它是什么。
一個常見的模式是讓一個線程產生內容,另一個線程做一些有用的東西。 這被稱為生產者 - 消費者模式。 在這種情況下,對於誰或什么嘗試SetBar()
以及嘗試GetBar()
內容沒有混淆。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.