请查看下面的课程并告诉我以下代码是否是线程安全的。我的问题是,一个类的static
方法和该方法调用单例实例的方法。此外,static
实例调用Runnable
方法。所以我要求你们看看代码 - static
方法,它在多线程环境中调用singleton的方法 - 是否安全?
如果你回答我的问题,我将非常感激。
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();
}
}
}
答案 0 :(得分:1)
这不安全,因为这种情况可能发生:
Thread 1 Thread 2
-------- --------
test instance != null
test instance != null
finds it is
finds it is
creates, assigns
creates, assigns
returns
returns
从本质上讲,这不再是单身人士了。
另请注意,您无法保证线程将返回哪个创建的实例,因为singletonInstance
甚至不易变形! p>
轻松修复,因为你的构造函数什么都不做:
private static final SingletonCLS INSTANCE = new SingletonCLS();
public static SingletonCLS getInstance() { return INSTANCE; }
其他可能的解决方案:
答案 1 :(得分:0)
首先,我认为你不需要单身人士。单例类中没有实例变量。 该方法可能非常静态。因此,它的线程安全在上下文中不需要Singleton。
其次,您的Singleton错误(如果需要)。请参阅 Effective Java Item 71。 尝试使用(lazy initialization holder class idiom)。
第二次反复打开同一个文件可能不是一个好主意。更好地读取和缓存内存中的数据,然后尝试查找id。在这种情况下,您将需要一个SingleTon对象。
答案 2 :(得分:0)
您的getIntance()
方法不是线程安全的。这可能导致创建多个SingletonCls
对象,如上面的答案所述。
要使用延迟实例化获取类的Singleton版本,您应该使用以下代码:
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