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();
        }
    }
}
4

3 回答 3

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; }

其他可能的解决方案:

  • 使用枚举;
  • 使用惰性初始化持有者类。
于 2013-07-04T16:02:35.263 回答
0

首先,我认为您在这里不需要单例。您在单例类中没有实例变量。该方法可以是静态的很好。因此,它在不需要 Singleton 的上下文中是线程安全的。

其次,您的单身人士是错误的(如果需要)。请参考Effective Java Item 71. try using (lazy initialization holder class idiom)

其次,一次又一次地打开同一个文件可能不是一个好主意。更好地读取和缓存内存中的数据,然后尝试查找 id。在这种情况下,您将需要一个 SingleTon 对象。

于 2013-07-04T16:34:22.757 回答
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

于 2013-07-04T16:55:06.103 回答