Java并发编程中如何避免双重检查锁漏洞?
- 内容介绍
- 文章标签
- 相关推荐
本文共计922个文字,预计阅读时间需要4分钟。
单例模式在实际工作和面试中出现的频率较高,double-checked lock 是单例模式中常见的实现方式:
javapublic class SimpleSingleton4 { private static SimpleSingleton4 INSTANCE;
private SimpleSingleton4() {}
public static SimpleSingleton4 getInstance() { if (INSTANCE==null) { synchronized (SimpleSingleton4.class) { if (INSTANCE==null) { INSTANCE=new SimpleSingleton4(); } } } return INSTANCE; }}
单例模式在实际工作或面试中出现的频率更高,double-checked lock是单例常见实现:
<b>public</b> <b>class</b> SimpleSingleton4 {<b>private</b> <b>static</b> SimpleSingleton4 INSTANCE;
<b>private</b> SimpleSingleton4() {
}
<b>public</b> <b>static</b> SimpleSingleton4 getInstance() {
<b>if</b> (INSTANCE == <b>null</b>) {
<b>synchronized</b> (SimpleSingleton4.<b>class</b>) {
<b>if</b> (INSTANCE == <b>null</b>) {
INSTANCE = <b>new</b> SimpleSingleton4();
}
}
}
<b>return</b> INSTANCE;
}
}
这段代码有问题:
<b>public</b> <b>static</b> SimpleSingleton4 getInstance() {
<b>if</b> (INSTANCE == <b>null</b>) {<font><i>//1</i></font><font>
<b>synchronized</b> (SimpleSingleton4.<b>class</b>) {</font><font><i>//2</i></font><font>
<b>if</b> (INSTANCE == <b>null</b>) {</font><font><i>//3</i></font><font>
INSTANCE = <b>new</b> SimpleSingleton4();</font><font><i>//4</i></font><font>
}
}
}
<b>return</b> INSTANCE;</font><font><i>//5</i></font><font>
}
</font>
你希望按1, 2, 3, 4, 金额 5顺序执行。
但是Java虚拟机实际上会做一些优化,重新排列一些代码指令。重排后的顺序可能会变成: 1, 3, 2, 4, 5,这样在多线程的情况下也会创建多个实例。重新排列的代码可能如下所示:
<b>public</b> <b>static</b> SimpleSingleton4 getInstance() {
<b>if</b> (INSTANCE == <b>null</b>) {<font><i>//1</i></font><font>
<b>if</b> (INSTANCE == <b>null</b>) {</font><font><i>//3</i></font><font>
<b>synchronized</b> (SimpleSingleton4.<b>class</b>) {</font><font><i>//2</i></font><font>
INSTANCE = <b>new</b> SimpleSingleton4();</font><font><i>//4</i></font><font>
}
}
}
<b>return</b> INSTANCE;</font><font><i>//5</i></font><font>
}
</font>
有什么解决办法?
答:您可以将volatile关键字添加到 的定义中INSTANCE。具体代码如下:
public class
<b>private</b> <b>volatile</b> <b>static</b> SimpleSingleton7 INSTANCE;<b>private</b> SimpleSingleton7() {
}
<b>public</b> <b>static</b> SimpleSingleton7 getInstance() {
<b>if</b> (INSTANCE == <b>null</b>) {
<b>synchronized</b> (SimpleSingleton7.<b>class</b>) {
<b>if</b> (INSTANCE == <b>null</b>) {
INSTANCE = <b>new</b> SimpleSingleton7();
}
}
}
<b>return</b> INSTANCE;
}
} 关键字可以保证多线程的volatile可见性但不保证原子性,也可以禁止指令重排序。
双重检查锁的机制不仅保证了线程安全,而且相比直接锁,提高了执行效率,节省了内存空间。
本文共计922个文字,预计阅读时间需要4分钟。
单例模式在实际工作和面试中出现的频率较高,double-checked lock 是单例模式中常见的实现方式:
javapublic class SimpleSingleton4 { private static SimpleSingleton4 INSTANCE;
private SimpleSingleton4() {}
public static SimpleSingleton4 getInstance() { if (INSTANCE==null) { synchronized (SimpleSingleton4.class) { if (INSTANCE==null) { INSTANCE=new SimpleSingleton4(); } } } return INSTANCE; }}
单例模式在实际工作或面试中出现的频率更高,double-checked lock是单例常见实现:
<b>public</b> <b>class</b> SimpleSingleton4 {<b>private</b> <b>static</b> SimpleSingleton4 INSTANCE;
<b>private</b> SimpleSingleton4() {
}
<b>public</b> <b>static</b> SimpleSingleton4 getInstance() {
<b>if</b> (INSTANCE == <b>null</b>) {
<b>synchronized</b> (SimpleSingleton4.<b>class</b>) {
<b>if</b> (INSTANCE == <b>null</b>) {
INSTANCE = <b>new</b> SimpleSingleton4();
}
}
}
<b>return</b> INSTANCE;
}
}
这段代码有问题:
<b>public</b> <b>static</b> SimpleSingleton4 getInstance() {
<b>if</b> (INSTANCE == <b>null</b>) {<font><i>//1</i></font><font>
<b>synchronized</b> (SimpleSingleton4.<b>class</b>) {</font><font><i>//2</i></font><font>
<b>if</b> (INSTANCE == <b>null</b>) {</font><font><i>//3</i></font><font>
INSTANCE = <b>new</b> SimpleSingleton4();</font><font><i>//4</i></font><font>
}
}
}
<b>return</b> INSTANCE;</font><font><i>//5</i></font><font>
}
</font>
你希望按1, 2, 3, 4, 金额 5顺序执行。
但是Java虚拟机实际上会做一些优化,重新排列一些代码指令。重排后的顺序可能会变成: 1, 3, 2, 4, 5,这样在多线程的情况下也会创建多个实例。重新排列的代码可能如下所示:
<b>public</b> <b>static</b> SimpleSingleton4 getInstance() {
<b>if</b> (INSTANCE == <b>null</b>) {<font><i>//1</i></font><font>
<b>if</b> (INSTANCE == <b>null</b>) {</font><font><i>//3</i></font><font>
<b>synchronized</b> (SimpleSingleton4.<b>class</b>) {</font><font><i>//2</i></font><font>
INSTANCE = <b>new</b> SimpleSingleton4();</font><font><i>//4</i></font><font>
}
}
}
<b>return</b> INSTANCE;</font><font><i>//5</i></font><font>
}
</font>
有什么解决办法?
答:您可以将volatile关键字添加到 的定义中INSTANCE。具体代码如下:
public class
<b>private</b> <b>volatile</b> <b>static</b> SimpleSingleton7 INSTANCE;<b>private</b> SimpleSingleton7() {
}
<b>public</b> <b>static</b> SimpleSingleton7 getInstance() {
<b>if</b> (INSTANCE == <b>null</b>) {
<b>synchronized</b> (SimpleSingleton7.<b>class</b>) {
<b>if</b> (INSTANCE == <b>null</b>) {
INSTANCE = <b>new</b> SimpleSingleton7();
}
}
}
<b>return</b> INSTANCE;
}
} 关键字可以保证多线程的volatile可见性但不保证原子性,也可以禁止指令重排序。
双重检查锁的机制不仅保证了线程安全,而且相比直接锁,提高了执行效率,节省了内存空间。

