9

我有一个单例类:

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变量 (a HashMap),有一些方法可以在类中添加和删除学生。

在我的应用程序中,可能有多个线程使用这个SchoolgetInstance(),然后添加和删除学生。为了使访问(尤其是对 students 实例的访问)是线程安全的,我正在考虑synchorized为方法使用关键字getInstanc(),例如:

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

但我认为我的微不足道的改变只能确保在多线程环境中只创建一个实例。 School我还需要做什么才能使其线程安全以通过多个线程访问 students 实例。有任何好的建议或意见,谢谢!

4

4 回答 4

5

留下关于单例是否邪恶的对话,让我们只考虑您School班级中的线程安全问题:

  • 共享对象是“懒惰”创建的——这需要同步以避免创建两个 ; 实例School。您已正确识别并修复了此问题。但是,由于初始化School不会花费太多时间,因此您不妨通过急切地getInstance()初始化来做一个简单的 getter 。school = new School()
  • School 内部的 hash map - 并发访问 hash map 会导致异常。您需要围绕添加、删除和迭代学生的代码添加同步以避免这些异常。
  • 访问个别学生——一旦调用者得到一个Student对象,他们可能会同时开始修改它。因此Student对象需要自己的并发保护。
于 2013-09-22T13:18:19.127 回答
0

HashMap 实现不是线程安全的,因此如果多个线程同时对其进行操作,可能会发生不好的事情。一个快速修复是使地图本身同步

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

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

一个线程安全的替代方案HashMapConcurrentHashMap

于 2013-09-22T13:15:08.047 回答
0

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

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

Collections.synchronizedMap(new HashMap());

于 2013-09-22T13:16:50.940 回答
0

您可以使用ConcurrentHashMapCollections.synchronizedMap

这篇文章给出了很好的解释

于 2013-09-22T13:18:45.477 回答