2013-07-04 61 views
0

請看下面的類,告訴我下面的代碼是否是線程安全的。我的問題的關鍵是,一個類的static方法和該方法調用單例實例的方法。另外,static方法由Runnable實例調用。所以我問你們看代碼 - static方法,它在多線程環境中調用單例方法 - 是否安全?單身和多線程

如果你回答我的問題,我將非常感激。

import java.io.BufferedReader; 
import java.io.FileReader; 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
import java.util.StringTokenizer; 

public class SingletonCls { 
    private static SingletonCls singletonInstance = null; 

    private SingletonCls() { 
    } 

    public static SingletonCls getIntance() { 
     if (SingletonCls.singletonInstance == null) { 
      singletonInstance = new SingletonCls(); 
     } 
     return SingletonCls.singletonInstance; 
    } 

    public List<Map<String, String>> call(String id) throws Exception { 
     List<Map<String, String>> list = new ArrayList<Map<String, String>>(); 
     BufferedReader br = null; 
     final String col = "col"; 
     try { 
      br = new BufferedReader(new FileReader("test.txt")); 
      String lineStr = null; 
      while ((lineStr = br.readLine()) != null) { 
       StringTokenizer st = new StringTokenizer(lineStr, ","); 
       int colIdx = 1; 

       if (lineStr.startsWith(id)) { 
        Map<String, String> map = new HashMap<String, String>(); 
        while (st.hasMoreTokens()) { 
         String value = st.nextToken(); 
         map.put(col + (colIdx++), value); 
        } 
        list.add(map); 
       } 
      } 

     } finally { 
      if (br != null) { 
       br.close(); 
      } 
     } 
     return list; 
    } 
} 


import java.io.IOException; 
import java.util.List; 
import java.util.Map; 

public class TestSingleTonCaller { 

    public static List<Map<String, String>> getData(String id) throws Exception { 
     List<Map<String, String>> list = SingletonCls.getIntance().call(id); 
     return list; 
    } 
} 



import java.io.IOException; 
import java.util.List; 
import java.util.Map; 

public class RunnableSingleTonExe implements Runnable { 
    private final String id; 

    public RunnableSingleTonExe(String inId) { 
     this.id = inId; 
    } 

    public void run() { 
     try { 
      List<Map<String, String>> list = TestSingleTonCaller 
        .getData(this.id); 
      System.out.println("thread id:" + this.id + " list > " 
        + (list == null ? "" : list.toString())); 
     } catch (IOException e) { 
      Thread.currentThread().interrupt(); 
      e.printStackTrace(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+3

由於您沒有正確創建單例,因此沒有。不能保證你只會有一個'SingletonCls'實例。在Java中對單例使用'enum' –

+2

'SingletonCls#getInstance'方法不是線程安全的。最好從頭開始初始化'singletonInstance',而不是延遲加載它。 –

+0

@Yonyou Ryu - As Brain和Luiggi表示,這不是線程安全的,有更好的方法。請參閱http://stackoverflow.com/questions/3635396/pattern-for-lazy-thread-safe-singleton-instantiation-in-java其他方式來做到這一點。 – lreeder

回答

1

這是不是安全的,因爲這種情況可能發生:

Thread 1    Thread 2 
--------    -------- 
test instance != null 
         test instance != null 
         finds it is 
finds it is 
creates, assigns 
         creates, assigns 
         returns 
returns 

從本質上說,這不是一個單身了。

請注意,您不能保證哪個創建的實例或者線程將返回,因爲singletonInstance甚至不是易變的!

容易修復,因爲你的構造函數什麼也不做:

private static final SingletonCLS INSTANCE = new SingletonCLS(); 

public static SingletonCLS getInstance() { return INSTANCE; } 

其他可能的解決方案:

  • 使用枚舉;
  • 使用一個懶惰的初始化持有者類。
+0

感謝您的回答。 :)我也告訴我的同事這種情況,但他沒有聽。但我可以確定代碼有錯誤。我會再次告訴他。再次感謝。 –

0

首先我不認爲你需要一個單身人士在這裏。您在單例類中沒有實例變量。 該方法可以是非常好的靜態。因此,它不需要Singleton的上下文中的線程安全。

二,你的單身人士是錯誤的(如果需要的話)。請參考Effective Java Item 71. 嘗試使用(懶惰初始化持有者類成語)

其次,一次又一次打開同一個文件可能不是一個好主意。更好地讀取和緩存內存中的數據,然後嘗試找到id。在這種情況下,您將需要一個SingleTon對象。

+0

謝謝你的回答。 N我也認爲懶惰初始化是沒有必要的。我會讓我的同事修復它。 –

0

您的getIntance()方法不是線程安全的。這可能導致創建上述答案中指定的多個對象SingletonCls。 爲了讓您的類的單版本延遲實例,你應該使用下面的代碼:

public class SingletonCls 
{ 
    public static SingletonCls getInstance() 
    { 
     return LazyClass.getInstance(); 
    } 
    private static class LazyClass 
    { 
     public static SingletonCls instance = new SingletonCls(); 
     public static SingletonCls getInstance() 
     { 
      return instance; 
     } 
    } 
} 

這依賴於一個事實,即內部類不加載,直到他們被引用。創建Singleton類的這種方式稱爲Initialization on Demand Holder

+0

感謝懶惰初始化持有者的鏈接。如果他堅持使用延遲初始化,我會讓我的同事知道鏈接並使用單身持有人。再次感謝。 –