2015-06-08 88 views
1

我有一個應用程序使用多個線程寫入下面的單個變量「theVar」。 99%的時間我有正確的數據,但有時一些數據丟失。我一直試圖解決這個問題近一個星期了,我真的很失落。它突然發生,我失去了數據,這是一個非常嚴重的問題。我究竟做錯了什麼?卡住更新由多個線程更新的單個變量

class Singleton { 
    private volatile Singleton instance; 
    private volatile String theVar = null; 
    private final Object lock = new Object(); 

    public void setVar(String newVar) { 
     synchronized (lock) { 
      theVar = newVar; 
     } 
    } 

    public String getVar() { 
     synchronized (lock) { 
      return theVar; 
     } 
    } 

    public void appendVar(String text) { 
     synchronized (lock) { 
      theVar += text; 
     } 
    } 

    protected Singleton() { 
    } 

    public static Singleton getInstance() { 
     Singleton instance = this.instance; 
     if (instance == null) { 
      synchronized (this) { 
       instance = this.instance; 
       if (instance == null) { 
        instance = this.instance = new Singleton(); 
       } 
      } 
     } 

     return instance; 
    } 
} 
+2

'instance'不是'volatile'。您的[DCL](https://en.wikipedia.org/wiki/Double-checked_locking)已損壞。此外,由於'lock'是一個實例變量,並且您總是鎖定整個實例方法,'synchronized'關鍵字有什麼問題? –

+0

謝謝Sotirios。我現在已經更新了這個問題。 – Karthik

+0

鮑里斯 - 感謝您的鏈接,我會看看DCL。因此,而不是鎖定變量「theVar」,我應該鎖定整個實例?什麼是同步? – Karthik

回答

2

好友,創建辛格爾頓我的建議是使用下面的方法是100%線程安全的,沒有同步問題,因爲它充分利用了Java的類加載機制。

Provider這個類會被加載一次(JVM永遠不會加載類兩次)當你getInstance()會被第一個線程被稱爲第一次,因此只有一個Singleton類的實例將存在。

即使2個線程將嘗試撥打同一時間getInstance()方法,但JVM將不會加載Provider兩次,因爲我們正在創造Singleton類實例的靜態初始化,這意味着對類加載的一部分,所以只有一個實例將存在。

就你而言,可能是2個線程完全相同的時間導致一些問題;試試這個,我希望你應該得到100%的結果。如果不是,那麼請提供如何運行相同的代碼。

public class Singleton { 
     private Singleton() { 
     } 

     private volatile String theVar = null; 

     public void setVar(String newVar) { 
      synchronized (this) { 
       theVar = newVar; 
      } 
     } 

     public String getVar() { 
      synchronized (this) { 
       return theVar; 
      } 
     } 

     public void appendVar(String text) { 
      synchronized (this) { 
       theVar += text; 
      } 
     } 

     private static class Provider { 
      static final Singleton INSTANCE = new Singleton(); 
     } 

     public static Singleton getInstance() { 
      return Provider.INSTANCE; 
     } 
    } 
+0

謝謝,這項技術工作得很好,到目前爲止我的所有運行都得到了正確的結果 – Karthik

+0

酷哥,很高興知道。 – hagrawal

2

嘗試這樣:

public enum Singleton { 
    INSTANCE; 
    private volatile String theVar = null; 


    public synchronized void setVar(String newVar) { 
     theVar = newVar; 
    } 

    public String getVar() { 
     return theVar; 
    } 

    public synchronized void appendVar(String text) { 
     theVar += text; 
    } 
    }