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
Instance variable in a Singleton class accessed by multiple threads
提问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:
在我的应用程序中,可能有多个线程使用这个School类getInstance(),然后添加和删除学生。为了使访问(尤其是对students实例的访问)成为线程安全的,我想synchorized为getInstanc()方法使用关键字,例如:
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 initializingSchooldoes not take much time, you might as well makegetInstance()a trivial getter by initializingschool = 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 theStudentobject 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
线程安全的替代方案HashMap是ConcurrentHashMap
回答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
您可以使用ConcurrentHashMap或Collections.synchronizedMap
Thisarticle gives a good explanation
这篇文章给出了很好的解释

