Java设计模式之单例模式
2016-02-01 10:27
435 查看
单例模式是Java设计模式中的创建型模式,也是一种很常用的设计模式。单例模式主要是为了保证应用程序中的某个实例有且只有一个,因为在某些应用场景下,一些对象只要有一个就可以了,如线程池、缓存、日志对象等。常见的单例模式有饿汉模式和懒汉模式。
1.饿汉模式
饿汉模式使用下面的步骤创建一个单例模式类:
(1)将构造方法私有化,不允许外部直接创建对象;
(2)创建类的唯一实例,使用private static 关键词修饰;
(3)提供一个用于获取实例的方法,使用public static关键词修饰,供外部使用;
下面就是主要代码:
在饿汉模式中,我们在类的加载过程中实例化对象,因此如果实例化对象很复杂的话,会导致类的加载过程很慢。不过,由于在类的加载中实例化对象,因此恶汉模式获取对象很快,也是线程安全的。
2.饿汉模式的变种
在加载类的过程中,可以使用静态代码块对对象实例化,原理上还是一样。代码如下:
3.懒汉模式
懒汉模式主体思想和饿汉模式相似,不同的是懒汉模式在第一次调用的时候进行实例化,而恶汉模式在类加载的时候进行实例化。代码如下;
懒汉模式和恶汉模式相比,由于在第一次调用的时候进行实例化,因此类的加载速度比较快,不过获取对象时由于要判断并进行实例化,因此没有饿汉模式快。同时,这种模式也不是线程安全的,当两个线程同时获取对象的时候可能会出错。
4.懒汉模式(方法同步)
为了实现线程安全,可以加上synchronized关键字。用它来修饰一个方法或一个代码块的时候,可以保证同一时刻只有一个线程执行该段代码。代码如下:
5.懒汉模式(双重检查锁定)
双重检查锁定就是在getInstance()方法内部再使用synchronized关键字修饰,进行双重检查。代码如下:
6.懒汉模式(静态内部类)
这种方式使用了classloader的机制来保证初始化instance时只有一个线程,它跟第1种和第2种方式不同的是(很细微的差别):第1种和第2种方式是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让它延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比第1和第2种方式就显得很合理。
下面使用下面的代码简单测试一下:
结果如下:
1.饿汉模式
饿汉模式使用下面的步骤创建一个单例模式类:
(1)将构造方法私有化,不允许外部直接创建对象;
(2)创建类的唯一实例,使用private static 关键词修饰;
(3)提供一个用于获取实例的方法,使用public static关键词修饰,供外部使用;
下面就是主要代码:
public class Singleton1 { private Singleton1(){} private static Singleton1 instance =new Singleton1(); public static Singleton1 getInstance() { return instance; } }
在饿汉模式中,我们在类的加载过程中实例化对象,因此如果实例化对象很复杂的话,会导致类的加载过程很慢。不过,由于在类的加载中实例化对象,因此恶汉模式获取对象很快,也是线程安全的。
2.饿汉模式的变种
在加载类的过程中,可以使用静态代码块对对象实例化,原理上还是一样。代码如下:
public class Singleton2 { private Singleton2() {} static{ instance=new Singleton2(); } private static Singleton2 instance=null; public static Singleton2 getInstance() { return instance; } }
3.懒汉模式
懒汉模式主体思想和饿汉模式相似,不同的是懒汉模式在第一次调用的时候进行实例化,而恶汉模式在类加载的时候进行实例化。代码如下;
public class Singleton3 { private Singleton3() {} private static Singleton3 instance=null; public static Singleton3 getInstance(){ if(instance==null) { instance=new Singleton3(); } return instance; } }
懒汉模式和恶汉模式相比,由于在第一次调用的时候进行实例化,因此类的加载速度比较快,不过获取对象时由于要判断并进行实例化,因此没有饿汉模式快。同时,这种模式也不是线程安全的,当两个线程同时获取对象的时候可能会出错。
4.懒汉模式(方法同步)
为了实现线程安全,可以加上synchronized关键字。用它来修饰一个方法或一个代码块的时候,可以保证同一时刻只有一个线程执行该段代码。代码如下:
public class Singleton4 { private Singleton4() {} private static Singleton4 instance=null; public static synchronized Singleton4 getInstance() { if(instance==null) { instance=new Singleton4(); } return instance; } }
5.懒汉模式(双重检查锁定)
双重检查锁定就是在getInstance()方法内部再使用synchronized关键字修饰,进行双重检查。代码如下:
public class Singleton5 { private Singleton5() {} private static Singleton5 instance=null; public static Singleton5 getInstance() { if(instance==null) { synchronized (Singleton5.class) { if(instance==null) { instance=new Singleton5(); } } } return instance; } }
6.懒汉模式(静态内部类)
public class Singleton6 { private static class SingletonHolder { private static final Singleton6 INSTANCE=new Singleton6(); } private Singleton6() {} public static final Singleton6 getInstance() { return SingletonHolder.INSTANCE; } }
这种方式使用了classloader的机制来保证初始化instance时只有一个线程,它跟第1种和第2种方式不同的是(很细微的差别):第1种和第2种方式是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让它延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比第1和第2种方式就显得很合理。
下面使用下面的代码简单测试一下:
public class test { public static void main(String[] args) { Singleton1 s1=Singleton1.getInstance(); Singleton1 s2=Singleton1.getInstance(); if(s1==s2) System.out.println("s1和s2是同一个对象"); else System.out.println("s1和s2不是同一个对象"); } }
结果如下:
相关文章推荐
- maven项目强制转换到jdk1.7 1.8
- 深入分析JavaWeb 5 -- Servlet开发
- JAVA泛型应用-获取容器运行时的泛型Class对象
- Eclipse快捷键
- 简单CXF操作之整合spring(二)
- Spring和Websocket相结合实现消息的推送
- springMVC动态生成验证码过程
- Eclipse 修改jsp、XML、 java、 HTML 每行显示的字数
- Java多线程-概念与原理
- java学习笔记(二)
- Java多线程入门
- JAVA List容器内部差异化比较工具类(咋个办呢 zgbn)
- Eclipse导入项目
- 【java】学习笔记(一)
- 2016蓝桥杯假期任务之《奇怪的比赛》
- 饿汉式单例与懒汉式单例的讨论
- Struts2 语法--result type
- java获取大文件的MD5、SHA1,CRC32码
- IoDH 实现的单例模式
- Java 解析 XML