java设计模式---(1)单例模式

单例模式
定义: 确保一个类只有一个实例, 而且自行实例化并向整个系统提供这个实例
保证只有一个实例,只能是不让外面访问的类的构造方法,所以就构造方法写成私有的,向整个系统提供一个实例那么就只能定义一个static的实例返回回去了,所以代码可以这样写:

public class Singelton {

	private static Singelton singelton = new Singelton();

	private Singelton(){ // 构造方法私有化,就不能new一个Singelton对象了
	}
	
	public static Singelton getSingelton() { // 通过getSingelton()来获取已经准备好了的对象
		return singelton;
	}
}

验证结果:

	public static void main(String[] args) {
		Singelton s1 = Singelton.getSingelton();
		Singelton s2 = Singelton.getSingelton();
		System.out.println(s1.equals(s2)); // true
	}

结果说明2次调用返回的是同一个对象,其实这个没什么好验证的,static 修饰的singelton对象在内存里面必然是独一份。
上面这个写法就是通常所说的饱汉模式,所谓饱汉模式就是对象事先已经new好了,就像是吃饱了的。对应的就有个饿汉模式了,饿汉模式是事先不new这个对象(先饿着),等到用的时候再new(要说这样有什么好呢,大约就是可以在类加载的时候少占的资源,毕竟少实例化一个static对象),其他地方跟上面的饱汉模式一样。
于是把上面的饱汉模式改一下,成了下面这样:

public class SingeltonHungry {

	private static SingeltonHungry hungry = null;

	private SingeltonHungry() { // 构造方法私有化,就不能new一个Singelton对象了
	}

	public static SingeltonHungry getSingelton() { // getSingelton()来获取对象,如果没有就创建,有就直接返回
		if (hungry == null) {
			hungry = new SingeltonHungry();
		}
		return hungry;
	}
}

在单线程下就不验证了,跟上面一样,返回的都是一个对象。但是在多线程的情况下就不一样了,因为有个hungry == null判断,然后才new一个新对象。所以在hungry对象最开始是null的时候如果2个线程同时执行上面的判空,然后都是true,然后就都去new了自己的对象了,这就不是单例了。
先写个线程类:

public class TestThread implements Runnable {
	@Override
	public void run() {
		SingeltonHungry singelton = SingeltonHungry.getSingelton();
		System.out.println("SingeltonHungry的hashCode:"+singelton.hashCode());
	}
}

然后来进行测试:

public static void main(String[] args) {
	Thread t1 = new Thread(new TestThread());
	Thread t2 = new Thread(new TestThread());
	t1.start();
	t2.start();
}

输出结果是:

SingeltonHungry的hashCode:1734172372
SingeltonHungry的hashCode:1232133915

说明2个线程各自创建了一个实例。所以这样的话就不是单例了。所以要改一下,给getSingelton()方法加个同步锁:

public class SingeltonHungry {
	private static SingeltonHungry hungry = null;

	private SingeltonHungry() { // 构造方法私有化,就不能new一个Singelton对象了
		System.out.println("call constructor"); // 看调用了几次构造方法
	}

	public static synchronized SingeltonHungry getSingelton() { // getSingelton()来获取对象,如果没有就创建,有就直接返回
		if (hungry == null) {
			hungry = new SingeltonHungry();
		}
		return hungry;
	}
}

再次使用上面的测试方法来测试一下2个线程来创建实例的情况,输出结果是:

call constructor
SingeltonHungry的hashCode:1481297610
SingeltonHungry的hashCode:1481297610

只输出一次“call constructor” 并且两个线程得到的对象是hashCode是一样的,这足以说明2个线程创建最终得到的对象是同一个。
总结一下,单例模式3个点:
1.私有化构造方法,让别人不能自主实例化对象
2.自己提供一个方法来创建一个静态对象。
3.单例模式有2个类型:饱汉模式、饿汉模式(要注意多线程问题)

猜你喜欢

转载自blog.csdn.net/u012843361/article/details/84569032
今日推荐