同步单例的正确使用?
所以我正在考虑建立一个业余爱好项目,这是一种临时性的事情,只是为了温习我的编程/设计。
它基本上是一个多线程网络蜘蛛,更新相同的数据结构对象->int。
因此,为此使用数据库绝对是大材小用,我唯一能想到的是用于包含我的数据结构的线程安全单例。 http ://web.archive.org/web/20121106190537/http://www.ibm.com/developerworks/java/library/j-dcl/index.html
是否有我应该考虑的不同方法?
So I am thinking about building a hobby project, one off kind of thing, just to brush up on my programming/design.
It's basically a multi threaded web spider, updating the same data structure object->int.
So it is definitely overkill to use a database for this, and the only thing I could think of is a thread-safe singleton used to contain my data structure. http://web.archive.org/web/20121106190537/http://www.ibm.com/developerworks/java/library/j-dcl/index.html
Is there a different approach I should look in to?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
双重检查锁定已被证明是不正确且有缺陷的(至少在 Java 中是这样)。 搜索或查看维基百科条目了解确切原因。
首先也是最重要的是程序的正确性。 如果您的代码不是线程安全的(在多线程环境中),那么它就被破坏了。 正确性优先于性能优化。
为了正确起见,您必须同步整个
getInstance
方法或静态初始化它
Double-checked locking has been proven to be incorrect and flawed (as least in Java). Do a search or look at Wikipedia's entry for the exact reason.
First and foremost is program correctness. If your code is not thread-safe (in a multi-threaded environment) then it's broken. Correctness comes first before performance optimization.
To be correct you'll have to synchronize the whole
getInstance
methodor statically initialize it
在网络爬虫中对数据库使用延迟初始化可能不值得。 延迟初始化增加了复杂性并持续影响速度。 一种合理的情况是,很有可能永远不需要数据。 此外,在交互式应用程序中,它可用于减少启动时间并提供速度的错觉。
对于像网络爬虫这样的非交互式应用程序来说,它肯定需要其数据库立即存在,延迟初始化不太合适。
另一方面,网络爬虫很容易并行化,并且将从多线程中受益匪浅。 使用它作为掌握 java.util.concurrent 库的练习是非常值得的。 具体来说,请查看
ConcurrentHashMap
和ConcurrentSkipListMap< /code>,
这将允许多个线程读取和更新共享地图。
当你摆脱延迟初始化时,最简单的单例模式是这样的:
关键字
final
是这里的关键。 即使您为单例提供static
“getter”而不是允许直接字段访问,使单例final
也有助于确保正确性并允许 JIT 编译器进行更积极的优化。Using lazy initialization for the database in a web crawler is probably not worthwhile. Lazy initialization adds complexity and an ongoing speed hit. One case where it is justified is when there is a good chance the data will never be needed. Also, in an interactive application, it can be used to reduce startup time and give the illusion of speed.
For a non-interactive application like a web-crawler, which will surely need its database to exist right away, lazy initialization is a poor fit.
On the other hand, a web-crawler is easily parallelizable, and will benefit greatly from being multi-threaded. Using it as an exercise to master the
java.util.concurrent
library would be extremely worthwhile. Specifically, look atConcurrentHashMap
andConcurrentSkipListMap
, which will allow multiple threads to read and update a shared map.When you get rid of lazy initialization, the simplest Singleton pattern is something like this:
The keyword
final
is the key here. Even if you provide astatic
"getter" for the singleton rather than allowing direct field access, making the singletonfinal
helps to ensure correctness and allows more aggressive optimization by the JIT compiler.如果您的生命取决于几微秒,那么我建议您将资源锁定优化到真正重要的地方。
但在这种情况下,这里的关键字是爱好项目!
这意味着,如果同步整个 getInstance() 方法,则在 99.9% 的情况下都不会出现问题。 我不建议以任何其他方式这样做。
稍后,如果您通过分析证明 getInstance() 同步是项目的瓶颈,那么您可以继续优化并发性。 但我真的怀疑这会给你带来麻烦。
杰奇!
If your life depended on a few microseconds then I would advise you to optimize your resource locking to where it actually mattered.
But in this case the keyword here is hobby project!
Which means that if you synchronized the entire getInstance() method you will be fine in 99.9% of all cases. I would NOT recommend doing it any other way.
Later, if you prove by means of profiling that the getInstance() synchronization is the bottleneck of your project, then you can move on and optimize the concurrency. But I really doubt it will cause you trouble.
Jeach!
尝试一下 Bill Pugh 按需初始化的解决方案。
该解决方案在不同的 Java 编译器和虚拟机上是最可移植的。
该解决方案是线程安全的,不需要特殊的语言结构(即易失性和/或同步)。
http://en.wikipedia.org/wiki/Singleton_pattern#The_solution_of_Bill_Pugh
Try the Bill Pugh solution of initialization on demand holder idiom.
The solution is the most portable across different Java compilers and virtual machines.
The solution is thread-safe without requiring special language constructs (i.e. volatile and/or synchronized).
http://en.wikipedia.org/wiki/Singleton_pattern#The_solution_of_Bill_Pugh
正如 Joshua Bloch 在他的书《Effective Java 第二版》中所说,我也同意单元素枚举类型是实现单例的最佳方式。
as Joshua Bloch argues in his book "effective java 2nd edition" I also agree that a single element enum type is the best way to implement a singleton.
如果您查看该文章的最底部,您将看到仅使用静态字段的建议。 这就是我的倾向:您并不真正需要延迟实例化(因此您不需要
getInstance()
既是访问器又是工厂方法)。 您只想确保您拥有且只有其中一件。 如果您确实需要对此类事物进行全局访问,我会使用 最底部的代码示例:请注意,单例现在是在安装静态字段期间构建的。 这应该可行,并且不会面临潜在的错误同步的线程风险。
综上所述,也许您真正需要的是现代 JDK 中可用的线程安全数据结构之一。 例如,我是 ConcurrentHashMap:线程安全,而且我不必编写代码(FTW!)。
If you look at the very bottom of that article, you'll see the suggestion to just use a static field. That would be my inclination: you don't really need lazy instantiation (so you don't need
getInstance()
to be both an accessor and a factory method). You just want to ensure that you have one and only one of these things. If you really need global access to one such thing, I'd use that code sample towards the very bottom:Note that the Singleton is now constructed during the installation of static fields. This should work and not face the threading risks of potentially mis-synchronizing things.
All that said, perhaps what you really need is one of the thread-safe data structures available in the modern JDKs. For example, I'm a big fan of the ConcurrentHashMap: thread safety plus I don't have to write the code (FTW!).
为什么不创建一个数据结构作为依赖注入传递给每个线程。 这样你就不需要单身人士了。 您仍然需要确保线程安全。
Why don't you create a data structure you pass to each of the threads as dependency injection. That way you don't need a singleton. You still need to make the thread safe.
您引用的文章仅讨论如何创建单例对象(在本例中可能是一个集合)线程安全。 您还需要一个线程安全的集合,以便集合操作也按预期工作。 确保单例中的底层集合是同步的,可能使用 ConcurrentHashMap。
The article you referenced only talks about making the creation of the singleton object, presumably a collection in this case, thread-safe. You also need a thread-safe collection so that the collection operations also work as expected. Make sure that the underlying collection in the singleton is synchronized, perhaps using a ConcurrentHashMap.
查看这篇文章在 C# 中实现单例模式
Check out this article Implementing the Singleton Pattern in C#
怎么样:
How about: