设计模式 之 单例模式
保证系统中一个类只有一个实例。
使用场景:
- 需要频繁实例化的对象;
- 创建时消耗资源过多,又常被使用的对象;
常见单例模式
1、饿汉式
package com.foruo.learn.designmode.singleton;
/**
* 单例 - 饿汉式(即类被加载时实例化对象)
* @author GaoYuan
* @date 2018/5/4 上午8:09
*/
public class SingletonDemoEntity {
/** 注意 static */
private static SingletonDemoEntity singletonDemoEntity = new SingletonDemoEntity();
/** 注意 private */
private SingletonDemoEntity(){}
public static SingletonDemoEntity getInstance(){
return singletonDemoEntity;
}
public static void main(String[] args){
MyThread myThread = new MyThread();
Thread thread1 = new Thread(myThread);
Thread thread2 = new Thread(myThread);
Thread thread3 = new Thread(myThread);
thread1.start();
thread2.start();
thread3.start();
//此处可见三次打印相同内容,则表示是同一个对象
}
}
class MyThread extends Thread{
@Override
public void run() {
System.out.println(SingletonDemoEntity.getInstance().hashCode());
}
}
2、懒汉式 - 普通 - 线程不安全 不推荐
package com.foruo.learn.designmode.singleton;
/**
* 单例 - 懒汉式(即类加载时没有实例化,调用取得实例的方法getInstance()的时候才实例化对象)
* @author GaoYuan
* @date 2018/5/4 上午8:09
*/
public class SingletonDemoEntity2 {
/** 注意 static 并且没有初始化 */
private static SingletonDemoEntity2 singletonDemoEntity;
/** 注意 private */
private SingletonDemoEntity2(){}
/** 注意 synchronized */
public static synchronized SingletonDemoEntity2 getInstance(){
if(singletonDemoEntity == null){
singletonDemoEntity = new SingletonDemoEntity2();
}
return singletonDemoEntity;
}
public static void main(String[] args){
MyThread2 myThread = new MyThread2();
Thread thread1 = new Thread(myThread);
Thread thread2 = new Thread(myThread);
Thread thread3 = new Thread(myThread);
thread1.start();
thread2.start();
thread3.start();
//此处可见三次打印相同内容,则表示是同一个对象
}
}
class MyThread2 extends Thread{
@Override
public void run() {
System.out.println(SingletonDemoEntity2.getInstance().hashCode());
}
}
3、懒汉式 - 双重锁 - 线程安全适用高并发 推荐
package com.foruo.learn.designmode.singleton;
/**
* 单例 - 懒汉式 - 双重锁(即类加载时没有实例化,调用取得实例的方法getInstance()的时候才实例化对象)
* @author GaoYuan
* @date 2018/5/4 上午8:09
*/
public class SingletonDemoEntity3 {
/** 注意 static 并且没有初始化 */
private static SingletonDemoEntity3 singletonDemoEntity = null;
/** 注意 private */
private SingletonDemoEntity3(){}
/**
* 注意 synchronized 不在方法上,而在if里面,这样只有第一次才进行同步,之后的每次调用因为已经有对象,则不会再进入同步方法中
* 高并发的场景下,又要使用懒汉式,则推荐使用 此方法
* */
public static SingletonDemoEntity3 getInstance(){
if(singletonDemoEntity == null){
synchronized (SingletonDemoEntity3.class){
if(singletonDemoEntity == null) {
singletonDemoEntity = new SingletonDemoEntity3();
}
}
}
return singletonDemoEntity;
}
public static void main(String[] args){
MyThread3 myThread = new MyThread3();
Thread thread1 = new Thread(myThread);
Thread thread2 = new Thread(myThread);
Thread thread3 = new Thread(myThread);
thread1.start();
thread2.start();
thread3.start();
//此处可见三次打印相同内容,则表示是同一个对象
}
}
class MyThread3 extends Thread{
@Override
public void run() {
System.out.println(SingletonDemoEntity3.getInstance().hashCode());
}
}
比较
撇开2,比较1饿汉式与3懒汉式
-
1饿汉式 在类加载的时候就创建实例对象,不管后续是否被调用,也有可能浪费一定的
空间
,但省去了每次调用判断的时间
。 -
3懒汉式(线程安全)在第一次调用时进行同步判断,但也仅仅是第一次需要同步,之后的每次只需要进行简单的if判断即可,相比较饿汉式多耗费些
时间
,如果从来没有被调用,则不会占据内存空间
。
综述:
- 懒汉式需要考虑线程安全;
- 不要用反射调用单例;
来源:oschina
链接:https://my.oschina.net/u/3720017/blog/1806559