设计模式之——单例模式

java语言里面有三种经典的设计模式:单例模式、工厂模式、代理模式。

一、单例模式:

单例模式所解决的问题是:保证一个类在内存中的对象唯一性。

单例模式特点:

1、一个类只实例化一个对象,保证对象唯一性

2、构造器私有化

3、必须自行创建这个实例

4、必须向整个系统提供这个实例,即有一个public修饰的方法。

 

单例模式有多中写法,其中饿汉式和懒汉式比较常用。

 一、饿汉式单例模式:(线程安全)

1 public class SingelModel{
2     private static SingelModel singel=new SingelModel();
3     private SingelModel(){}
4     public static SingelModel getInstance(){
5         return singel;
6     }
7 }    

 

  饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。

 

 

二、懒汉式单例模式:(非线程安全)

 

 1 public class SingelModel {
 2     private static SingelModel singel=null;
 3     private SingelModel(){}
 4     public static SingelModel getInstance(){
 5         if(singel=null){
 6             singel=new SingelModel();
 7         }
 8         return singel;
 9     }          
10 }    

 

 

SingelModel 通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,SingelModel 的唯一实例只能通过getInstance()方法访问。

但是以上懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton实例,要实现线程安全,有以下三种方式,都是对getInstance这个方法改造,保证了懒汉式单例的线程安全。



二(一)、懒汉模式,在getInstance方法上加同步
 1 public class SingelModel{
 2     private static SingelModel singel=null;
 3     private SingelModel(){}
 4     public static syhcronized SingelModel getInstance(){
 5         if(singel==null){
 6             singel=new SingelModel();
 7         }
 8         return singel;
 9     }
10 }    

 在方法调用上加了同步,虽然线程安全了,但是每次都要同步,会影响性能,毕竟99%的情况下是不需要同步的

 

 

二(二)、懒汉模式,双重检查锁定
 1 public class SingelModel{
 2     private static SingelModel singel=null;
 3     private SingelModel(){}
 4     public static SingelModel getInstance(){
 5         if(singel==null){
 6             synchronized(SingelModel.class){
 7                 if(singel==null){
 8                     singel=new SingelModel();
 9                 }
10             }
11         }
12         return singel;
13     }
14 }

 在getInstance中做了两次null检查,确保了只有第一次调用单例的时候才会做同步,这样也是线程安全的,同时避免了每次都同步的性能损耗。这两种懒汉式即实现了线程安全,又避免了同步带来的性能影响。




饿汉式和懒汉式区别:
饿汉式就是类一旦加载,就把单例初始化完成,保证了在调用getInstance()方法时单例已经存在。
懒汉式就是比较懒,只有在调用getInstance()方法时才去初始化这个单例。

关于线程安全:
饿汉式时天生的线程安全,可以直接用于多线程而不用考虑会出现问题。
懒汉式本身并不是线程安全的,为了安全才会有上面两种写法
在getInstance方法上加同步,双重检查锁定

关于资源加载和性能:
饿汉式在类创建的同时就会实例化一个静态对象,之后不管用不用这个单例都会占据一定的内存,但相应的,第一次调用时速度会很快。
而懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。

 

 下面是一个双重检查锁定懒汉式单例模式例子:

 

 1 package singel;
 2 
 3 /*
 4  * 单例模式举例说明
 5  * 
 6  */
 7 public class TestMain {
 8     public static void main(String[] args) {
 9         SingelModel s1 = SingelModel.getSingel();
10         s1.setAge(10);
11         SingelModel s2 = SingelModel.getSingel();
12         s2.setAge(20);
13 
14         s1.printinfo();
15         s2.printinfo();
16         
17         System.out.println(s1==s2);
18     }
19 }
20 
21 class SingelModel {
22     int age;
23     private static SingelModel singelmodel = null;
24 
25     private SingelModel() {
26     }
27 
28     public static SingelModel getSingel() {
29         if (singelmodel == null) {
30             synchronized (SingelModel.class) {
31                 if (singelmodel == null) {
32                     singelmodel = new SingelModel();
33                 }
34             }
35         }
36         return singelmodel;
37     }
38 
39     public int getAge() {
40         return age;
41     }
42 
43     public void setAge(int age) {
44         this.age = age;
45     }
46 
47     public void printinfo() {
48         System.out.println("age:" + age);
49     }
50 }

 

 运行结果:

 1 age:20

2 age:20

3 true 

 

posted @ 2017-08-30 22:59  九零大叔芭蕉  阅读(510)  评论(0编辑  收藏  举报