单例模式

单例模式

1.单例模式属于创建型模式。确保一个类只有单个对象被创建,这个类提供了一种访问其唯一对象的方式,可以直接访问,不需要实例化该类的对象。

注意:

  • 1.单例类只能有一个实例;
  • 2.单例类必须自己创建自己唯一的实例;
  • 3.单例类必须给所有其他对象提供这一个实例。

2.使用条件:当想控制实例的数目的时候。比如一个班只有一个班主任,再比如Windows操作文件的时候必须是唯一实例。

3.优点:在内存只有一个实例,避免了内存的开销(频繁创建和销毁实例)

4.缺点:没有接口,不可继承。

5.关键思想:构造函数私有。

实现方法:

1.懒汉式,线程不安全。

描述:不支持多线程。

1
2
3
4
5
6
7
8
9
public class SingleObject{
private static SingleObject object;
private SingleObject(){}
public static SingleObject getObject(){
if(object==null)
object=new SingleObject();
return object;
}
}
2.懒汉式,线程安全。

描述:采用synchronize加锁保证单例,支持多线程。加锁影响效率

1
2
3
4
5
6
7
8
9
public class SingleObject{
private static SingleObject object;
private SingleObject(){}
public static synchronize SingleObject getObject(){ //采用synchronize
if(object==null)
object=new SingleObject();
return object;
}
}
3.饿汉式,线程安全。

描述:不用加锁,但类加载时就初始化,会浪费内存。

1
2
3
4
5
6
7
public class SingleObject{
private static SingleObject object=new SingleObject();//和懒汉式区别
private SingleObject(){}
public static SingleObject getObject(){
return object;
}
}
4.双重校验锁,线程安全

描述:采用双锁机制,在保证线程安全的情况下有较高性能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SingleObject{
private static SingleObject object;
private SingleObject(){}
public static SingleObject getObject(){
if(object==null){
synchronize(SingleObject.class){
if(object==null)
{
object=new SingleObject(); //存在隐患
}
}
}
return object;
}
}

在网上查阅发现双重锁还是有隐患,在实例化对象那一行,发生的事情有:

A: 分配内存空间

B:初始化对象

C:将对象指向刚分配的空间

但有些编译器可能因为性能原因,BC重排序,会将BC调换顺序,顺序成了ACB。

假设有两个线程A,B:

时间 Thread A Thread B
1 object=null
2 获取锁
3 检查到object=null
4 为object分配内存
5 将object指向内存空间
6 检查到object!=null
7 访问object(此时还未完成初始化)
8 初始化object

修改:在object前加上volatile关键字,重排序被禁止,所有的写操作都发生在读操作之后。

volatile作用:确保本条指令不会因为编译器的优化而省略。表示这个变量可能会意想不到的改变,这样,编译器就不会去假设这个变量的值了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SingleObject{
private static volatile SingleObject object;
private SingleObject(){}
public static SingleObject getObject(){
if(object==null){
synchronize(SingleObject.class){
if(object==null)
{
object=new SingleObject();
}
}
}
return object;
}
}