单例-饿汉式
/**
* @Title: Singleton.java
* @Package org.chisj.single
* @Description: TODO
* @author chisj chisj@foxmail.com
* @date 2017年3月24日
*/
package org.chisj.single;
// 单例模式确保某个类只有一个实例, 而且自行实例化并向整个系统提供这个实例。
// 线程池、日志对象、对话框、打印机、先看的驱动程序对象进程被设计成单例。
// 选择单例模式是为了避免不一致的状态,避免政出多头
/**
* ClassName: Singleton
* @Description: 懒汉式单例,在第一次调用的时候实例自己
* @author chisj chisj@foxmail.com
* @date 2017年3月24日
*/
public class Singleton {
// Singleton通过将构造方法限定为private, 避免了类在外部被实例化,
// 在同一个虚拟机范围内, Singleton的唯一实例化只能通过getInstance()方法访问
// 事实上, 通过Java反射机制是能够实现实例化构造方法为private类
// 基本上会使得所有的Java单例实现失效, 所以我们默认认为反射机制不存在
private Singleton() {}
private static Singleton single = null;
// 静态工厂方法
// 没有考虑线程安全问题, 所以是线程不安全的, 并发环境下很可能出现多个Singleton的实例
/*
public static Singleton getInstance() {
// 判断实例是否被创建初始化
if (single == null) {
// 没有创建实例对象的时候进行创建
single = new Singleton();
}
return null;
}
*/
// 加上synchronized同步
/*
public static synchronized Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
*/
// 双重检查锁定
/*
public static Singleton getInstance() {
if (single == null) {
synchronized (Singleton.class) {
if (single == null) {
single = new Singleton();
}
}
}
return single;
}
*/
// 静态内部类
// 这种方法比上面的1, 2都好一些, 既实现线程安全, 又避免了同步带来的性能问题
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static final Singleton geInstance() {
return LazyHolder.INSTANCE;
}
}
// 单例模式的实现方式有三种:懒汉式单例, 饿汉式单例, 登记式单例
// 单例模式的特点:
// 1.单例类只能有一个实例.
// 2.单例类必须自己创建自己的唯一实例.
// 3.单例类必须给所有其他对象提供这一实例.
单例-懒汉式
/**
* @Title: Singleton1.java
* @Package org.chisj.single
* @Description: TODO
* @author chisj chisj@foxmail.com
* @date 2017年3月24日
*/
package org.chisj.single;
/**
* ClassName: Singleton1
* @Description: 恶汉式单例类,在类初始化时已经自行实例化
* @author chisj chisj@foxmail.com
* @date 2017年3月24日
*/
public class Singleton1 {
private Singleton1() {}
private static final Singleton1 single = new Singleton1();
// 静态工厂方法
public static Singleton1 getInstance() {
return single;
}
}
// 说明
// 饿汉式在类床架的同时已经创建好一个静态的对象供系统使用, 以后不再改变, 所以天生是线程安全的
// 饿汉式和懒汉式区别
// 饿汉式的类一旦加载, 就把单例初始化完成, 保存getInstance的时候, 单例是已经存在的了
// 懒汉式比较懒, 只有当抵用getInstance的时候, 才回去初始这个单例
// 1.线程安全
// 饿汉式天生就是线程安全的, 可以直接用于多线程而不会出现问题.
// 懒汉式本身是非线程安全的, 为了实现线程安全有几种写法, 分别是上面的1、2、3, 这三种实现在资源加载和性能方面有些区别
// 2.资源加载和性能
// 饿汉式在类创建的同时就实例化一个静态对象出来, 不管之后会不会使用这个单例, 都会占据一定的内存,
// 但是相应的, 在第一次调用时速度也会更快, 因为其资源已经初始化完成。
// 单例模式为一个面向对象的应用程序提供了对象唯一的访问点, 不管她实现何种功能, 整个应用程序都会同享一个实例对象
单例--登记式
/**
* @Title: Singleton2.java
* @Package org.chisj.single
* @Description: TODO
* @author chisj chisj@foxmail.com
* @date 2017年3月24日
*/
package org.chisj.single;
import java.util.HashMap;
import java.util.Map;
// 登记式单例维护了一组单例类的实例, 将这些实例存放在一个Map(登记薄)中,
// 对于已经登记过的实例, 则从Map直接返回, 对于没有登记的, 则先登记, 然后返回.
/**
* ClassName: Singleton2
* @Description: 登记式单例, 类似于Spring里面的方法, 将类名注册, 下次从里面直接获取
* @author chisj chisj@foxmail.com
* @date 2017年3月24日
*/
public class Singleton2 {
private static Map<String, Singleton2> map = new HashMap<String, Singleton2>();
static {
Singleton2 single = new Singleton2();
map.put(single.getClass().getName(), single);
}
// 保护的默认构造
protected Singleton2() {};
public static Singleton2 getInstance(String name) {
if (name == null) {
name = Singleton2.class.getName();
System.out.println("name == null " + " ---> name = " + name);
}
if (map.get(name) == null) {
try {
map.put(name, (Singleton2) Class.forName(name).newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO: handle exception
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO: handle exception
e.printStackTrace();
}
}
return map.get(name);
}
// 一个示意性的商业方法
public String about() {
return "Hello, I am RegSingleton.";
}
public static void main(String[] args) {
Singleton2 single2 = Singleton2.getInstance(null);
System.out.println(single2.about());
}
}