Java设计模式——单例模式
2016-06-23 17:30
281 查看
单例模式的意图是为了确保在一个JVM中某一个类有且仅有一个实例,并未他提供一个全局的访问点。有以下一个好处:
1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。
3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令
员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。
单例模式在多线程编程下也是很重要的一个知识点。
从单例的生成方式来分可以分为以下2类:
一、饿汉式单例
package cn.wqy.singletonmode;
public class HungrySingleton {
// 私有化构造方法,防止其可以new对象
private HungrySingleton() {
}
private static HungrySingleton single = new HungrySingleton();
//天生线程安全
public static HungrySingleton getInstance() {
return single;
}
}
在用到这个类时,即对其中static变量进行了初始化,因此天生线程安全。
二、懒汉式单例
package cn.wqy.singletonmode;
public class LazySingleton {
// 私有化构造方法
private LazySingleton() {
}
private static LazySingleton single = null;
public static LazySingleton getInstance() {
if (single == null) {
return new LazySingleton();
} else {
return single;
}
}
}
这是最基本的懒汉式,Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一
实例只能通过getInstance()方法访问。但是以上懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能
出现多个Singleton实例。因此需要做如下修改:
①同步方法
package cn.wqy.singletonmode;
public class LazySingleton {
// 私有化构造方法
private LazySingleton() {
}
private static LazySingleton single = null;
public static synchronized LazySingleton getInstance() {
if (single == null) {
return new LazySingleton();
} else {
return single;
}
}
}
当多个线程同时同时访问同一个对象object的getInstance方法时,由synchronized关键字解决并发问题。但是这种方式会每次都检查
是否有同步的并发问题,很影响效率。
但是synchronized方法需要慎用,因为:
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
②双重锁定
package cn.wqy.singletonmode;
public class LazySingleton {
// 私有化构造方法
private LazySingleton() {
}
private static LazySingleton single = null;
public static LazySingleton getInstance() {
if (single == null) {
synchronized (LazySingleton.class) {
if (single == null) {
single = new LazySingleton();
}
}
}
return single;
}
}利用的是synchronized块,且在每次判断同步前先判断了一下是否为空,为空才去考虑同步,解决并发问题。理论上提高了效率。
③静态内部类
package cn.wqy.singletonmode;
public class LazySingleton {
// 私有化构造方法
private LazySingleton() {
}
public static class lazyHolder{
private static final LazySingleton single = new LazySingleton();
}
public static final LazySingleton getInstance(){
return lazyHolder.single;
}
}
这种方法比上面两种方法好,同时线程安全。
1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。
3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令
员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。
单例模式在多线程编程下也是很重要的一个知识点。
从单例的生成方式来分可以分为以下2类:
一、饿汉式单例
package cn.wqy.singletonmode;
public class HungrySingleton {
// 私有化构造方法,防止其可以new对象
private HungrySingleton() {
}
private static HungrySingleton single = new HungrySingleton();
//天生线程安全
public static HungrySingleton getInstance() {
return single;
}
}
在用到这个类时,即对其中static变量进行了初始化,因此天生线程安全。
二、懒汉式单例
package cn.wqy.singletonmode;
public class LazySingleton {
// 私有化构造方法
private LazySingleton() {
}
private static LazySingleton single = null;
public static LazySingleton getInstance() {
if (single == null) {
return new LazySingleton();
} else {
return single;
}
}
}
这是最基本的懒汉式,Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一
实例只能通过getInstance()方法访问。但是以上懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能
出现多个Singleton实例。因此需要做如下修改:
①同步方法
package cn.wqy.singletonmode;
public class LazySingleton {
// 私有化构造方法
private LazySingleton() {
}
private static LazySingleton single = null;
public static synchronized LazySingleton getInstance() {
if (single == null) {
return new LazySingleton();
} else {
return single;
}
}
}
当多个线程同时同时访问同一个对象object的getInstance方法时,由synchronized关键字解决并发问题。但是这种方式会每次都检查
是否有同步的并发问题,很影响效率。
但是synchronized方法需要慎用,因为:
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
②双重锁定
package cn.wqy.singletonmode;
public class LazySingleton {
// 私有化构造方法
private LazySingleton() {
}
private static LazySingleton single = null;
public static LazySingleton getInstance() {
if (single == null) {
synchronized (LazySingleton.class) {
if (single == null) {
single = new LazySingleton();
}
}
}
return single;
}
}利用的是synchronized块,且在每次判断同步前先判断了一下是否为空,为空才去考虑同步,解决并发问题。理论上提高了效率。
③静态内部类
package cn.wqy.singletonmode;
public class LazySingleton {
// 私有化构造方法
private LazySingleton() {
}
public static class lazyHolder{
private static final LazySingleton single = new LazySingleton();
}
public static final LazySingleton getInstance(){
return lazyHolder.single;
}
}
这种方法比上面两种方法好,同时线程安全。
相关文章推荐
- eclipse的svn插件连接osc的代码仓库时候报错的解决办法
- Exception in thread "main" java.lang.ClassCastException: $Proxy13
- Java NIO 学习
- java处理日期工具类(一)
- 个人理解JAVA反射
- 实现图片合并功能
- (转)Java中的容器详细总结
- java 调用WebService【转】
- java学习day13
- Java解析xml文件
- IntelliJ IDEA 2016.1 创建Maven Java Web项目(图解)
- Java解析xml文件
- java自学之旅(2.3)关于Calendar类常用方法
- java写入、读取excel文件1
- Java 集合系列目录(Category)
- java中集合与数组之间的转化
- Spring AOP 实现功能权限校验功能
- Java定时任务4:Jcrontab使用数据库存储数据源
- java 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
- 技术演绎之 [ java ] 面向对象引入