2011-11-13 27 views
2

我讀過Java的Java類是不可變的,也是線程安全的,但我仍然對字符串的引用賦值是否是線程安全感到困惑。如何安全地在Java中設置/獲取字符串?

第一個問題:如果在線程B調用Foo.getString(),在下面的代碼是線程安全的線程A調用Foo.setString()

Class Foo { 
    String aString; 
    public String getString() { 
     return aString; 
    } 
    public void setString(s) { 
     aString = s; 
    } 
} 

第二個問題:如果上面的代碼不是線程安全的,使用的ReentrantLock,我怎麼寫Foo.getString()方法?

Class Foo { 
    String aString; 
    ReentrantLock aLock; 
    public String getString() { 
     aLock.lock(); 
     return aString; 
     aLock.unlock(); // This line will be unreachable. How to fix?? 
    } 
    public void setString(s) { 
     aLock.lock(); 
     aString = s; 
     aLock.unlock(); 
    } 
} 

我必須使用ReentrantLock,因爲我需要使用tryLock(超時)功能。

+0

如果我的問題都回答了,我會接受答案。謝謝。 – Lee

回答

2

問題1: 這取決於你的線程安全的,Eric Lippert wrote a very good blog post about it here ... 但在宣佈ASTRING揮發性意味着將意味着任何讀取不同的線程保證是正確的。

問題2:

使用try ... finally結構,finally塊如解鎖:

public String getString() { 
    try {   
    aLock.lock(); 
    return aString; 
    } finally { 
    aLock.unlock(); 
    } 
} 

public void setString(s) { 
    try {   
    aLock.lock(); 
    aString = s; 
    } finally { 
    aLock.unlock(); 
    } 
} 
+0

想知道更多關於我的第一個問題。 – Lee

+0

@李見更新。 –

1

使用synchronized關鍵字:

public synchronized String getString() { 
     return aString; 
    } 

    public synchronized void setString(s) { 
     aString = s; 
    } 
+0

對不起,在我的情況下,我不得不使用ReentrantLock,因爲我需要使用tryLock(超時)功能。 – Lee

+0

好的,沒有注意到。所以最好能像其他海報所建議的那樣,在finally塊中解鎖。 – aleroot

+0

爲什麼你需要使用tryLock?這是功課還是這樣的? – James

2

製作aString波動是所有你需要在這種情況下(即在寫入後讀取總會看到最新的值) - 使方法同步並不是特別有用,因爲我們只能執行如果你想做更多的工作(比如說「如果字符串是XYZ然後給它分配XYA」),那麼你就需要更高級別的同步。即同步和易失性給你相同的保證(除了明顯的差異,如果我們使用同步在其他地方的顯着差異)

如此不穩定是足夠和更高性能,但同步也一樣 - 唯一的性能差異,你可能會注意到如果你有很多爭用的訪問,但否則它並不重要 - 同步是非常優化的非競爭訪問至少在熱點(但我假設對所有現代JVM同樣如此)。

相關問題