设计模式之单利
单利设计模式是非常常用的一种设计模式,也是提高效率的一种设计思路。单利其实还是很发杂的。
很多朋友其实早就接触了单利只是没有留意而已, Servlet 就是一个单实例多线程的,所以Servlet存在线程安全
问题! 今天和大家分享一下单利的原理。
一.饿汉式单利
现在很多程序员不关心JAVA的内存分配,以为JVM都可以搞定那么这是错误的。如果你对内存分配不是很在行还是要
了解一下,单利和内存分配,多线程是密不可分的。 饿汉式是比较简单, 看代码。
/*
饿汉式单利设计模式
*/
class Singleten_ehanshi
{
private static Singleten_ehanshi s = new Singleten_ehanshi();
private Singleten_ehanshi()
{
}
public static Singleten_ehanshi getInstance()
{
return s;
}
}
为什么说单利可以提高效率但有线程安全问题?
当JVM通过类加载器加载类的时候Static并没有分配在堆内存上,而是在静态区(这是还没有类实例加载)。
这样保证了一个实例在内存中不会有多余的实例分配在堆内存中,所以效率会高一些。既然是Static的实例那么所有线程过来
多可以修改公共的东西(成员)所以安全性有问题,这和Servlet一样的问题。
二.懒汉式单利
/*
单利设计模式: 懒汉式。
多线程的问题解决.
*/
class Singleten_lanhanshi
{
private static Singleten_lanhanshi sgl = null;
private Singleten_lanhanshi()
{
}
public static Singleten_lanhanshi getInstace()
{
if(sgl == null) //减少锁的判断次数.
{
//这时候同步使用的是 字节码这个锁
synchronized(Singleten_lanhanshi.class)
{
if(sgl == null)
{
sgl = new Singleten_lanhanshi();
}
}
}
return sgl;
}
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
大家可能对程序中为什么加一把锁而疑惑,这是懒汉式中比较重要的东西,多线程的问题就是由此而引起的。
我们来解释下这段代码
if(sgl == null) //减少锁的判断次数.
{
//这时候同步使用的是 字节码这个锁
synchronized(Singleten_lanhanshi.class)
{
if(sgl == null)
{
sgl = new Singleten_lanhanshi();
}
}
}
大家对于第一个应该明白,就是为了减少线程对锁的判断次数。
为什么要加一把锁?我们用多线程来推理, 当地一个线程判断了实例为空后可能会成为等待状态(或冻结)如图
第二个线程进来加了一把锁,并且对静态区的对象实例化,注意这时候对象已经不为空了。
这线程一醒了他还停留在对象为空的时候,又去实例化了一次这就出现了错误,所以必须同步。
同步为什么用这样的锁而不是对象锁呢?
这就是内存分配了, 大家想想当类加载的时候Static的先于对象被加载进内存,这个时候内存中还没有任何对象所以对象
锁是不可能的, 但是静态区中有这个静态对象本身所以要用这把锁。