2015-09-25 148 views
1

我有一個類TestLogger,它有一個void方法log(String s),它可以被多個線程訪問。這裏是我的代碼Java多線程:線程安全數據結構與同步方法

public class TestLogger { 
    private static final StringBuffer buffer = new StringBuffer(); 

    public static void log(String s) { 
     buffer.append(s); 
    } 
} 

我不知道在這裏如果我使用的線程安全類StringBuffer,我還需要把synchronized關鍵字的方法log(String),以確保該方法的線程安全?這種方法怎麼樣

public static void log(String s, int type) { 
    if (type == 0) 
     buffer.append(s); 
    if (type == 1) 
     buffer.append("SOME HEADER " + s); 
} 

這裏類型沒有在方法日誌中修改。我需要使用synchronized關鍵字嗎?

在Java中,同步關鍵字和線程安全類都可以提供線程安全性。我不確定何時使用其中一個和另一個?

+0

如果使用緩衝區,則不需要同步,如果某些內容是「線程安全」,則一般規則可能使用同步本身 –

回答

2

由於此方法的任何實現最多隻能訪問buffer一次,因此您在技術上不需要同步該方法,但這是非常糟糕的做法。

首先,它非常脆弱。這是不夠,一些粗心的開發人員需要看看這種方法並決定以「優化」它(以更好的Java代碼!)你失去了StringBuffer的同步:

public static void log(String s, int type) { 
    if (type == 0) 
     buffer.append(s); 
    if (type == 1) 
     buffer.append("SOME HEADER ").optimize(s); 
} 

這段代碼顯示了兩個單獨的呼叫因此,如果您同時撥打log('A', 1)log('B',1),那麼您的緩衝區可能會很好,爲"SOME HEADER SOME HEADER AB"。其次,即使你沒有技術上的破壞同步,僅僅依靠StringBuffer來提供你的同步需求,你可能會發現輕微的行爲怪異。例如,考慮未來的要求,也記錄消息的時間:

public static void log(String s) { 
    Date d = new Date(); 
    buffer.append(d.toString() + " " + s); 
} 

如果有相當數量的併發調用這個方法,你可能會遇到線程A創建新Date實例,上下文切換到另一個線程完成整個方法,然後返回到線程A.這將使您的日誌看起來好像它正在向後移動,這絕對是而不是你想要的。

第三,也是最重要的是,將方法定義爲​​具有聲明性值。它傳達了這個方法在多線程上下文中的行爲方式,以及你如何期待兩個併發呼叫相互作用。在爲他人設計的公用事業功能中,這是至關重要的。

0

因爲StringBuffer是線程安全的,所以你不需要在它周圍有另一個同步點(這是同步會做的)。

0

StringBuilder在java中不是線程安全的。所以你可以使用線程安全的StringBuffer

​​關鍵字可以以兩種不同的方式使用。

同步方法:它使該方法是線程安全的。

public synchronized static void log (String log) { 
     buffer.append(log); 
} 

同步聲明:使其與指定對象線程安全的。

public static void log(String log) { 
    synchronized (buffer) { 
     buffer.append(log); 
    } 
} 
2

以及如何對這種方法...

你兩種方法同樣線程安全的(或不!看線以下)。無論調用哪種方法,都會發生同樣的情況:只有一個字符串將被添加到共享緩衝區中。


使用線程安全對象不會使程序變得線程安全。您可以自行決定「線程安全」的含義。

當有人告訴你某些是線程安全的時,他們所希望的是,調用類的方法的多個線程無法使它們中的任何一個以「錯誤」的方式行爲。

「錯誤」是什麼意思?這得看情況。當然,任何不同意班級文件的行爲都是錯誤的。通常,任何與合理程序員所期望的不同的行爲都可能被錯誤地稱爲錯誤。

在StringBuffer的情況下,這裏是「線程安全」的意思是:這意味着,:

  • 你不會找到你的程序沒有把緩存中的緩衝器什麼。
  • 從緩衝區中找不到任何東西缺失您的程序放在那裏。
  • 您不會發現兩個不同字符串中的字符相互交錯,最後,
  • 如果您可以證明字符串A是在追加字符串B之前追加的,那麼字符串A將出現在字符串之前的輸出中B.

你舉的例子方法的調用都是線程安全僅憑每一個使一個線程安全的共享對象只是一個電話的事實。

如果您有例如幾個共享對象不過,這時候的對象的單個線程安全可能加起來線程安全的整個算法。

+0

非常感謝。這澄清了我對線程安全的擔憂。 – CMZS