[英]Double Checked Locking in Singleton
here is my custom class for singleton pattern.这是我的单例模式自定义类。 in this code, I use double-checked locking as below.在这段代码中,我使用如下双重检查锁定。 As I read many posts on some source, they say that double check is useful because it prevents two concurrent threads run at same times make two different objects.当我在某些来源上阅读了许多帖子时,他们说双重检查很有用,因为它可以防止同时运行的两个并发线程生成两个不同的对象。
public class DoubleCheckLocking {
public static class SearchBox {
private static volatile SearchBox searchBox;
// private constructor
private SearchBox() {}
// static method to get instance
public static SearchBox getInstance() {
if (searchBox == null) { // first time lock
synchronized (SearchBox.class) {
if (searchBox == null) { // second time lock
searchBox = new SearchBox();
}
}
}
return searchBox;
}
}
I still don't understand above code so much.我还是不太明白上面的代码。 What is the problem, if two threads together run same line of code when instance is null ?有什么问题,如果两个线程在 instance 为 null 时一起运行同一行代码?
if (searchBox == null) {
synchronized (SearchBox.class) {
if (searchBox == null) {
searchBox = new SearchBox();
}
}
}
When that appear.当那个出现。 both two threads will see object is null.两个线程都会看到对象为空。 then both synchronize.然后两者同步。 and then, they check again, and still see it null .然后,他们再次检查,仍然看到它 null 。 and create two different objects.并创建两个不同的对象。 OOOPS.哎呀。
Please explain for me.请为我解释。 What have I understand wrong ?我理解错了什么?
Thanks :)谢谢 :)
No, since you are obtaining lock on the SearchBox.class
, only one thread will enter the synchronized block at a time.不,由于您正在获取对SearchBox.class
锁定,因此一次只有一个线程会进入同步块。 So the first thread enters then finds searchBox
is null and creates it and then leaves the synchronized block, then the second thread enter the block then it finds that the searchBox
is not null because the first thread already created it so it will not create a new instance of searchBox
.所以第一个线程进入然后发现searchBox
为空并创建它然后离开同步块,然后第二个线程进入块然后它发现searchBox
不为空,因为第一个线程已经创建了它所以它不会创建一个新的searchBox
实例。
The double checked pattern is used to avoid obtaining the lock every time the code is executed.双重检查模式用于避免每次执行代码时都获得锁定。 If the call are not happening together then the first condition will fail and the code execution will not execute the locking thus saving resources.如果调用没有同时发生,那么第一个条件将失败,代码执行将不会执行锁定,从而节省资源。
Let's look at this code:让我们看看这段代码:
1 if (searchBox == null) {
2 synchronized (SearchBox.class) {
3 if (searchBox == null) {
4 searchBox = new SearchBox();
5 }
6 }
Let's try to reason about this.让我们试着推理一下。 Let's say we have two threads A
and B
and let's assume that at least one of them reaches line 3 and observes searchBox == null
is true
.假设我们有两个线程A
和B
并假设其中至少一个到达第 3 行并观察到searchBox == null
为true
。 Two threads can not both be at line 3 at the same time because of the synchronized
block.由于synchronized
块,两个线程不能同时在第 3 行。 This is the key to understanding why double-checked locking works.这是关键,理解为什么双重检查锁定的工作方式。 So, it must the case that either A
or B
made it through synchronized
first.因此,必须是A
或B
首先通过synchronized
。 Without loss of generality, say that that thread is A
.不失一般性,假设该线程是A
。 Then, upon seeing searchBox == null
is true, it will enter the body of the statement, and set searchBox
to a new instance of SearchBox
.然后,当看到searchBox == null
为真时,它会进入语句的主体,并将searchBox
设置为SearchBox
一个新实例。 It will then eventually exit the synchronized
block.然后它将最终退出synchronized
块。 Now it will be B
's turn to enter: remember, B
was blocked waiting for A
to exit.现在轮到B
进入:记住, B
被阻塞等待A
退出。 Now when it enters the block, it will observe searchBox
.现在当它进入块时,它会观察searchBox
。 But A
will have left just having set searchBox
to a non- null
value.但是A
将只剩下将searchBox
设置为非null
值。 Done.完毕。
By the way, in Java, the best way to implement a singleton is to use a single-element enum
type.顺便说一下,在 Java 中,实现单例的最好方法是使用单元素enum
类型。 From Effective Java :从有效的Java :
While this approach has yet to be widely adopted, a single-element enum type is the best way to implement a singleton.虽然这种方法尚未被广泛采用,但单元素枚举类型是实现单例的最佳方式。
This double check lock is only necessary if you are worried about many threads calling the singleton simultaneously, or the cost of obtaining a lock in general.仅当您担心多个线程同时调用单例或一般情况下获取锁的成本时,才需要此双重检查锁。
Its purpose is to prevent unnecessary synchronization, thereby keeping your code fast in a multi-threaded environment.它的目的是防止不必要的同步,从而使您的代码在多线程环境中保持快速。
Check out this link for more information. 查看此链接了解更多信息。
If you are running in Java 1.5 or greater, and you use the volatile
keyword in your double-check locked mechanism, it will work fine.如果您在 Java 1.5 或更高版本中运行,并且您在双重检查锁定机制中使用volatile
关键字,它会正常工作。 As you are using the volatile
keyword, your example is not broken according to the same link above.当您使用volatile
关键字时,根据上面的相同链接,您的示例没有被破坏。
if (searchBox == null) { //1
synchronized (SearchBox.class) {
if (searchBox == null) { //2
searchBox = new SearchBox();
}
}
}
}
So basically the outer if
is used to prevent redundant locks - it lets all thread know that there is already an object and they don't need to lock/do anything.所以基本上外部if
用于防止冗余锁 - 它让所有线程知道已经有一个对象并且他们不需要锁定/做任何事情。 And the inner if
is used to let a concurrent thread know whether another has already created the object or not.内部if
用于让并发线程知道另一个线程是否已经创建了该对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.