前言
- 上文提到了两种懒汉式单例加载问题,针对多线程我提出了一种加锁的方式避免重复实例化。本来以为就解决了问题。虽然测试中我没有发现问题,但是请教了一个老前辈他给我指出了其中的不足。
问题分析
- 加锁就是让获取对象时能够线性执行。但是因为我们锁是加载if上的。
- 当A线程获取锁成功时,并且完成了对象的创建后,B线程中对象并没有及时的得到刷新,这个时候B线程也获取到A线程释放的锁了,那么还是会重复创建对象。
- 这部分就涉及到线程对象都是拷贝在每个线程中的。前辈还说没有遇到问题是因为我运气好。实际上还是存在一定的安全隐患的。
解决方案
- 其实遇到问题是好事,只有遇到问题才能说明我们有进步的空间,更确切的说我们有进步的机会。如果我们贪图安逸那么只会错失高峰。
- 上面的问题其实涉及到一个知识点就是Java中线程中对象时如何刷新的。真实对象时在内存中线程中都是在内存中拷贝的一个副本。线程修改对象实际上是修改副本然后回传内存。内存中在分发给各个线程。这个过程就是我们上述的原因出现。
- volatile关键字就能很好的解决,他能够做到当内存变量出现改变时第一时间刷新最新值。
volatile private static Person person = null;
private SingleFactory()
{
}
public static Person getIstance()
{
try
{
Thread.sleep(30);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
synchronized (SingleFactory.class)
{
if (person == null)
{
person = new Person();
}
}
return person;
}
总结
- 一个简单的单例模式我居然能够学到synchronize和volatile两个关键字,简直赚了;关于这两个关键字设计到计算机底层原理,这里我们就不在深入研究了