Singleton类中的实例变量由多个线程访问

时间:2013-09-22 13:10:51

标签: java multithreading performance singleton

我有一个单身人士课程:

public class School {
    private HashMap<String, String> students;

    private static School school;

    private School(){
        students = new HashMap<String, String>();   
    }

    public static School getInstance(){
       if(school == null){
           school = new School();
       }
       return school;
    }

    //Method to add student
    protected void addStudent(String id, String name){
          students.put(id,name);
    }
    //Method to remove student
    protected void removeStudent(String id){
          students.remove(id);
    }
}

正如您在上面所看到的,在单例类中,我有一个students变量(HashMap),有一些方法可以添加&amp;移除班上的学生。

在我的应用程序中,可能有多个线程使用此School类到getInstance(),然后添加&amp;删除学生。要使访问权限(特别是对 students 实例的访问权限)为线程安全,我打算使用{{1} } synchorized方法的关键字,如:

getInstanc()

但我认为我的微不足道的改变只能确保在多线程环境中只创建一个 public synchronized static School getInstance(){ if(school == null){ school = new School(); } return school; } 实例。我还需要做些什么来使线程安全,以便通过多个线程访问 School 实例。任何好的建议或评论都是值得的,谢谢!

4 个答案:

答案 0 :(得分:5)

关于单身人士是否是邪恶的谈话,让我们只考虑School班级中的线程安全问题:

  • 共享对象是“懒洋洋地”创建的 - 这需要同步以避免生成School的两个实例;您已正确识别并修复此问题。但是,由于初始化School并不需要花费太多时间,因此您可以通过急切地初始化getInstance()来使school = new School()变得微不足道。
  • 学校内的哈希映射 - 对哈希映射的并发访问将导致异常。您需要在代码周围添加同步,以添加,删除和迭代学生以避免这些异常。
  • 访问个别学生 - 一旦调用者获得Student个对象,他们可能会同时开始修改它。因此Student对象需要自己的并发保护。

答案 1 :(得分:0)

HashMap实现不是线程安全的,因此如果多个线程同时对它进行操作可能会发生错误。快速解决方法是making the map itself synchronized

    students = Collections.synchronizedMap(new HashMap<String, String>());

请注意,如果您在此地图上进行迭代,则还必须在synchronized块中进行迭代;否则其他线程可能会在您迭代时修改地图。

HashMap的线程安全替代方法是ConcurrentHashMap

答案 2 :(得分:0)

同步方法使它们的线程安全,这意味着一次只有一个线程可以执行该方法。

但是,在上述情况下,我建议仅同步addStudent和removeStudent方法。或者您也可以使用 -

同步学生哈希地图

Collections.synchronizedMap(new HashMap());

答案 3 :(得分:0)

您可以使用ConcurrentHashMapCollections.synchronizedMap

This文章给出了一个很好的解释