2013-07-04 23 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

感谢懒惰初始化持有者的链接。如果他坚持使用延迟初始化,我会让我的同事知道链接并使用单身持有人。再次感谢。 –