单例模式使用场景:
需要频繁和创建和销毁的对象
创建对象耗时过多或消耗资源过多,即重量级对象,但又经常用到的对象
工具类对象,频繁访问数据库或文件的对象(如数据源、session工厂等)
Runtime就是精典的饿汉单例模式应用
public class Runtime {
private static Runtime currentRuntime = new Runtime();
/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class <code>Runtime</code> are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the <code>Runtime</code> object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
public static void main(String[] args) {
//精典的饿汉模式
Runtime.getRuntime();
Singleton s1 = Singleton.Instance;
Singleton s2= Singleton.Instance;
System.out.println(s1==s2);
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
s1.sayHello();
}
/**
* 饿汉式(静态变量)
* 优点:写法简单,在类装载时完成实例化,避免了线程同步问题
* 缺点:装载时完成实例化,没有达到懒加载效果,如果不使用这个实例,造成内存浪费。
* 结论:可用,会造成内存浪费。
*/
public class Singleton {
//1. 构造器私有化,外部不能new
private Singleton(){
}
//2. 内部创建实类对象
private final static Singleton instance = new Singleton();
//3. 对外提供静态方法,返回对象实例
public static Singleton getInstance(){
return instance;
}
}
/**
* 饿汉式(静态代码块)
* 优点:写法简单,在类装载时完成实例化,避免了线程同步问题
* 缺点:装载时完成实例化,没有达到懒加载效果,如果不使用这个实例,造成内存浪费。
* 结论:可用,会造成内存浪费。
*/
public class Singleton {
//1. 构造器私有化,外部不能new
private Singleton(){
}
//2. 静态代码块中创建实类对象
private final static singleton.type2.Singleton instance;
static{
instance = new singleton.type2.Singleton();
}
//3. 对外提供静态方法,返回对象实例
public static singleton.type2.Singleton getInstance(){
return instance;
}
}
/**
* 懒汉式(线程不安全)
* 只能在单线程下使用
*/
public class Singleton {
private Singleton(){};
private static Singleton instance;
public static Singleton GetInstance(){
if(instance==null){
instance= new Singleton();
}
return instance;
}
}
/**
* 懒汉式(同步方法解决线程安全)
* 效率低
*/
public class Singleton {
private static Singleton instance;
private Singleton(){};
public static synchronized Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
}
/**
* 同步代码块解决线程安全
* 不推荐
*/
public class Singleton {
private static Singleton instance;
private Singleton(){};
public static Singleton getInstance(){
if(instance==null){
synchronized (Singleton.class){
instance=new Singleton();
}
}
return instance;
}
}
/**
* 双重检查
* 线程安全,延迟加载,效率较高
* 推荐使用
双重校验锁法会有怎样的情景:
* STEP 1. 线程A访问getInstance()方法,因为单例还没有实例化,所以进入了锁定块。
* STEP 2. 线程B访问getInstance()方法,因为单例还没有实例化,得以访问接下来代码块,而接下来代码块已经被线程1锁定。
* STEP 3. 线程A进入下一判断,因为单例还没有实例化,所以进行单例实例化,成功实例化后退出代码块,解除锁定。
* STEP 4. 线程B进入接下来代码块,锁定线程,进入下一判断,因为已经实例化,退出代码块,解除锁定。
* STEP 5. 线程A初始化并获取到了单例实例并返回,线程B获取了在线程A中初始化的单例。
* 理论上双重校验锁法是线程安全的,并且,这种方法实现了lazyloading。
*/
public class Singleton {
private static volatile Singleton instance;
private Singleton(){};
public static Singleton getInstance(){
if(instance==null){
synchronized (Singleton.class){
if(instance==null){
instance=new Singleton();
}
}
}
return instance;
}
}
/**
* 静态内部类不会在单例加载时就加载,而是在调用getInstance()方法时才进行加载,
* 达到了类似懒汉模式的效果, *而这种方法又是线程安全的。
*/
public class Singleton {
private static class SingletonInstantce{
private final static Singleton instance = new Singleton();
}
private Singleton(){
}
public static Singleton getInstance(){
return SingletonInstantce.instance;
}
}
/**
* 枚举法
*/
public enum Singleton {
Instance;
public void sayHello(){
System.out.println("hello");
}
}