java 单例模式 懒汉和饿汉

单线程下的单例模式

定义:

确保一个类只有一个实例,并提供一个全局访问点。

单例代码:

package wfb.pattern;


public class Singleton {
	private static Singleton instance;
	private Singleton() {
		System.out.println("实例化了一个新的单例");
	}
	public static Singleton getInstance() {
		if(instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
}

测试代码:

package wfb.patthernTest;

import org.junit.Test;

import wfb.pattern.Singleton;

public class SingletonTest {
	@Test
	public void testSinglon1() {
		Singleton singlon1 = Singleton.getInstance();
		Singleton singlon2 = Singleton.getInstance();
	}
	@Test
	public void testSingleton2() throws Exception {
		while(true) {
			new Thread(new Runnable() {
				public void run() {
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					Singleton singlon = Singleton.getInstance();
				}
			}).start();
		}
	}
}

测试结果:

单线程 :
java 单例模式 懒汉和饿汉
多线程 :
java 单例模式 懒汉和饿汉

原因分析:

    如果多个线程同时走到if(instance == null)的判断语句,会因为还未创建实例而进入到实例化代码,从而导致了单件被实例化多次。换句话说,根本原因是if(instance == null) instance = new Singleton()这两步操作不是原子性的。
为此,我们有两种解决方法:
1.在类加载后就初始化instance,之后就不在需要创建实例了。
2.用同步包起这两步操作,从而使得它具有原子性。
懒汉和饿汉模式就这两种方法分别给出了多线程下单例模式的解决方案。

多线程下的单例模式

饿汉代码:

package wfb.pattern;
//饿汉模式通过提前初始化一个实例来解决多线程问题
public class SingletonHungry {
	private static SingletonHungry instance = new SingletonHungry();
	private SingletonHungry() {
		System.out.println("实例化了一个新的单例");
	}
	public static SingletonHungry getInstance() {
		return instance;
	}
}

饿汉测试:

@Test
	public void testSingletonHungry() throws Exception{
		while(true) {
			new Thread(new Runnable() {
				public void run() {
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					SingletonHungry singletonHungry = SingletonHungry.getInstance();
				}
			}).start();
		}
	}

饿汉结果:

java 单例模式 懒汉和饿汉

懒汉代码:

package wfb.pattern;
//懒汉模式通过同步解决多线程问题。
public class SingletonLazy {
	private static SingletonLazy instance;
	private SingletonLazy() {
		System.out.println("实例化了一个新的单例");
	}
	public static SingletonLazy getInstance() {
		if(instance != null) return instance;//为了增加效率,当拥有了实例后,我们直接返回实例。因为拥有了实例后,状态就跟饿汉一致了,显然不会发生线程问题。
		synchronized (SingletonLazy.class) {//因为是静态方法,所以用类做同步锁
			if(instance == null) instance = new SingletonLazy();
			return instance;
		}
	}
}

懒汉测试:

@Test
	public void testSingletonLazy() throws Exception{
		while(true) {
			new Thread(new Runnable() {
				public void run() {
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					SingletonLazy singletonLazy = SingletonLazy.getInstance();
				}
			}).start();
		}
	}

懒汉结果:

java 单例模式 懒汉和饿汉