Java 多线程访问的单例类中的实例变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18944184/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 12:45:48  来源:igfitidea点击:

Instance variable in a Singleton class accessed by multiple threads

javamultithreadingperformancesingleton

提问by Mellon

I have a singleton class:

我有一个单例类:

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

As you can see above, in the singleton class, I have a studentsvariable (a HashMap), there are methods to add & remove student in the class.

正如你在上面看到的,在单例类中,我有一个students变量 (a HashMap),有在类中添加和删除学生的方法。

In my application, there could be multiple threads using this Schoolclass to getInstance(), then adding & removing student. To make the access (especially the access tostudentsinstance) be thread safe, I am thinking to use synchorizedkeyword for getInstanc()method, like:

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

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

But I think my trivial change only can make sure only oneSchoolinstance be created in multi-thread environment. What else do I need to do in order to make it thread safe for accessing thestudentsinstance by multiple threads as well. Any good suggestion or comment is appreicated, thanks!

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

采纳答案by dasblinkenlight

Leaving the conversation on whether singletons are evil or not, let's consider only the thread safety issues in your Schoolclass:

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

  • The shared object is created "lazily"- this needs synchronization to avoid making two instances of School; you have correctly identified and fixed this issue. However, since initializing Schooldoes not take much time, you might as well make getInstance()a trivial getter by initializing school = new School()eagerly.
  • The hash map inside the School- concurrent access to the hash map will result in exceptions. You need to add synchronization around the code that adds, removes, and iterates students to avoid these exceptions.
  • Access to individual students- once the callers get a Studentobject, they may start modifying it concurrently. Therefore the Studentobject needs concurrency protection of their own.
  • 共享对象是“懒惰地”创建的- 这需要同步以避免创建两个实例School;您已正确识别并修复了此问题。但是,由于初始化School不需要太多时间,您不妨getInstance()通过school = new School()急切地初始化来制作一个简单的 getter 。
  • School 内部的哈希映射——并发访问哈希映射会导致异常。您需要在添加、删除和迭代学生的代码周围添加同步以避免这些异常。
  • 访问个别学生- 一旦调用者获得一个Student对象,他们就可以同时开始修改它。因此Student对象需要自己的并发保护。

回答by Joni

The HashMap implementation is not thread-safe, so bad things may happen if several thread operate on it at the same time. A quick fix is making the map itself synchronized:

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

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

Note that if you iterate on this map, the iteration also has to be made in a synchronizedblock; otherwise other threads may modify the map while you are iterating.

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

A thread-safe alternative to HashMapis ConcurrentHashMap

线程安全的替代方案HashMapConcurrentHashMap

回答by Vikas

Synchronizing method makes them thread safe it means only one thread can execute that method at a time.

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

However, in above situation, i would suggest to synchronized addStudent and removeStudent method only. Or you can synchronized students hash map also using -

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

Collections.synchronizedMap(new HashMap());

Collections.synchronizedMap(new HashMap());

回答by Srikanth Reddy Lingala

You can use a ConcurrentHashMapor a Collections.synchronizedMap

您可以使用ConcurrentHashMapCollections.synchronizedMap

Thisarticle gives a good explanation

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