设计模式之单例模式

1.单例模式

即保证整个系统只有一个实例对象

1.1使用场景可有:

1).数据缓存对象

2).工具方法

1.2实现方式:

通过对构造函数私有化类实现对象单例

2.单例的代码实现

2.1实现方式一

(懒汉式)

Singleton
public class Singleton {
	
	private static Singleton _instance = null;
	
	private Singleton(){
		System.out.println("初始化");
	}
	
	public static Singleton getInstance(){
		if(_instance == null){
			_instance = new Singleton();
		}
		return _instance;
	}

	public static void doSomething(){
		System.out.println("做点东西吧!");
	}
}
Client

public class Client{
     public static void main(){
        Singleton singleton = Singleton.getInstance();
        singleton.doSomething();
	System.out.println(singleton);
	singleton = Singleton.getInstance();
	System.out.println(singleton);
     }
}
上面这种方式存在问题,当有多线程时,会导致实例被创建多次。于是我们引入同步锁:

2.2同步锁优化

Singleton
public class Singleton{
	private static Singleton _instance = null;
	
	private Singleton(){}
		
	public static Singleton getInstance(){
		synchronized(Singleton.class){
			if(_instance == null){
				_instance = new Singleton();
			}
			return _instance;
		}
	}	
	public static void doSomething(){
		System.out.println("做点东西吧");
	}
}
Client:
public class Client{
	public static void main(String[] args){
		for(int i = 0;i < 10;i++){
			Thread t = new Thread(new Runable(){
				public void run(){
					Singleton singleton = Singleton.getInstnace();
					System.out.println(singleton);
				}
			});
			t.start();
		}
	}
}

如上,加入同步关键字后会引发效率问题,我们可以加入双检锁,缩小锁的范围

2.3使用双检锁

Singleton
public class Singleton {

	private static Singleton _instance = null;

	private Singleton() {
	}

	/**
	 * new Singleton() 这句话其实是包含三个逻辑 1.给Singleton实例创建空间 2.初始化Singleton的构造器
	 * 3.把Singleton这个实例的引用赋值给_instance (_instance就不为null了)
	 * 由于jvm运行期的优化,第二部和第三步的顺序是不能保证的 这样就会导致出现两种情况1,2,3或1,3,2
	 */
	public static Singleton getInstance() {
		if (_instance == null) {
			synchronized (Singleton.class) {
				if (_instance == null) {
					_instance = new Singleton();
				}
			}
		}
		return _instance;
	}

	public static void doSomething() {
		System.out.println("做点东西吧");
	}
}



Client


public class Client{
	public static void main(String[] args){
		for(int i = 0;i < 10;i++){
			Thread t = new Thread(new Runnable(){
				public void run(){
					Singleton singleton = Singleton.getInstance();
					System.out.println(singleton);
				}
			});
			t.start();
		}
	}
}
如上这种实现方式中 new  Singleton()包含三个逻辑:
1.给Singleton实例创建空间
2.初始化Singleton的构造器
3.把singleton这个实例的引用赋值给_instance (_instance就不为null了)

假如第一个线程调用获取实例的方法时,执行到new Singleton();这句话,只执行了1,3两个步骤,
这个时候_instance已经不为null了,但是构造器没有初始化完成,然后第二个线程进来,由于此时
_instance已经不为null了,所以在判读非空的时候就直接返回了,这时如果线程2使用这个构造器没
有初始化完成的singleton对象的话,就会报错!

解决方案有:
1.jdk1.5及1.5以后版本可以在变量中声明volatile关键字,让线程强制读取主内容中的变量,而不去读取变量副本。
2.通过饿汉式的单例模式来解决
3.使用静态类来保存instance

2.4使用volatile关键字

Singleton
public class Singleton {
	
	private static volatile Singleton _instance = null;
	
	private Singleton(){}
	
	public static Singleton getInstance(){
		if(_instance == null){
			synchronized(Singleton.class){
				if(_instance == null){
					_instance = new Singleton();
				}
			}
		}
		return _instance;
	}

	public static void doSomething(){
		System.out.println("做点东西吧!");
	}
}

2.5饿汉式

public class Singleton{
	
	private final static Singleton _instance = new Singleton();
	
	private Singleton(){
		System.out.println("初始化!");
	}
	
	public static Singleton getInstance(){
		return _instance;
	}
	
	public static void doSomething(){
		System.out.println("做点东西吧!");
	}
}

Client

public class Client {
	public static void main(String[] args) throws ClassNotFoundException {
		Class.forName("singleton.Singleton");
		Singleton.getInstance().doSomething();
	}
}

2.6静态类保存instance的方式

Singleton
public class Singleton{
	
	private static class SingletonHolder{
		static Singleton _instance = new Singleton();
	}
	
	private Singleton(){
		System.out.println("初始化!");
	}
	
	public static Singleton getInstance(){
		return SingletonHolder._instance;
	}
	
	public static void doSomething(){
		System.out.println("做点什么吧!");
	}
	
}

Client
public class Client {
	public static void main(String[] args) throws ClassNotFoundException {
		Class.forName("singleton.Singleton");
		Singleton.getInstance().doSomething();
	}
}


小结:在软件设计当中,我们应该遵循一个法则,简单,正确。不为了炫耀技术来实现需求,只有简单,正确的实现方式,它生命周期才是最长,因它可维护性高。所以选择懒汉还是饥汉的方式是根据具体的场景定的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值