标签:private 分析 volatil 创建 安全 效果 缓存 ESS 第三版
单例模式的意图:是为了确保一个类有且仅有一个实例,并为它提供一个全局访问点。
单例模式的要点有三个:
从实现角度来说,就是以下三点:
/**
* 饿汉式:在类加载时就创建单例对象。
* 使用规范 —— 确定会用到一次时可以使用,不然可能造成内存浪费
*/
public class Singleton_ehan {
public static void main(String[] args) {
System.out.println("使用饿汉式单例模式");
getInstance();
}
private Singleton_ehan(){}
/*
* 饿汉式 —— 静态常量
* 优点:写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题
* 缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。
* 如果从始至终从未使用过这个实例,则会造成内存的浪费
*/
// private static Singleton_ehan instance = new Singleton_ehan();
/*
* 饿汉式 —— 静态代码块
* 优缺点同上
*/
private static Singleton_ehan instance;
static{
instance = new Singleton_ehan();
}
public static Singleton_ehan getInstance(){
return instance;
}
}
/**
* 懒汉式:真正用到时才去实例化单例对象
* 【不推荐使用】
*/
public class Singleton_lanhan {
public static void main(String[] args) {
System.out.println("懒汉式");
getInstance();
}
private Singleton_lanhan(){}
private static Singleton_lanhan instance;
/**
* 懒汉式——第一版
* 优点:起到了Lazy Loading的效果,但是只能在单线程下使用。
* 缺点:如果在多线程下,一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,
* 这时便会产生多个实例。所以在多线程环境下不可使用这种方式
*/
// public static Singleton_lanhan getInstance(){
// if(instance == null){
// instance = new Singleton_lanhan();
// }
// return instance;
// }
/**
* 懒汉式——第二版(同步方法)
* 优点:解决了线程不安全问题
* 缺点:效率太低了,每个线程在想获得类的实例时候,执行getInstance()方法都要进行同步。
* 其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return就行了。
* 方法进行同步效率太低
*/
// public static synchronized Singleton_lanhan getInstance(){
// if(instance == null){
// instance = new Singleton_lanhan();
// }
// return instance;
// }
/**
* 懒汉式——第三版(同步代码块)
* 优缺点同上(不能使用)
*/
public static Singleton_lanhan getInstance(){
if(instance == null){
synchronized(Singleton_lanhan.class) {
instance = new Singleton_lanhan();
}
}
return instance;
}
}
/**
* Double Check:双重检查
* 优点:可以保证线程安全,延迟加载,效率较高
*【强烈推荐使用】
*/
public class Singleton_dc {
public static void main(String[] args) {
System.out.println("双重检查");
getInstance();
}
private Singleton_dc(){}
private static volatile Singleton_dc instance; //使用volatile关键字可以保证缓存一致性(内存可见性)
public static Singleton_dc getInstance(){
if(instance == null){
synchronized (Singleton_dc.class){
if(instance == null){
instance = new Singleton_dc();
}
}
}
return instance;
}
}
/**
* 静态内部类
* 分析:(1)类的静态属性只会在第一次加载类的时候初始化,所以在这里, JMM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入
* 采用了类装载的机制来保证初始化实例时只有一个线程
* (2)静态内部类方式在Singleton_static类被装载时并不会立即实例化 ——>
* 而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton_static的实例化。
* 优点:
* 避免了线程不安全,利用静态内部类特点实现延迟加载,效率高
* 【推荐使用】
*/
public class Singleton_static {
public static void main(String[] args) {
System.out.println("静态内部类");
getInstance();
}
private Singleton_static(){}
//定义静态内部类
private static class SingletonInstance{
private static final Singleton_static INSTANCE = new Singleton_static();
}
public static Singleton_static getInstance(){
return SingletonInstance.INSTANCE;
}
}
import org.omg.PortableInterceptor.INACTIVE;
/**
* 枚举
* 分析:借助JDK1.5中添加的枚举来实现单例模式。
* 优点:不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。
* 【这种方式是Effective Java作者Josh Bloch 提倡的方式——强推】
*/
public class Singleton_enum {
public static void main(String[] args) {
Singleton instance1 = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println(instance1.equals(instance2)); //true
System.out.println(instance1.hashCode()); //1956725890
System.out.println(instance2.hashCode()); //1956725890
instance1.sayOK(); //enum ok!
}
}
/**
* Enum就是一个普通的类,它继承自java.lang.Enum类
*/
enum Singleton{
INSTANCE; //对象
public void sayOK(){
System.out.println("enum ok!");
}
}
JDK中, java.lang.Runtime就是经典的单例模式 (饿汉式)
代码分析+Debug源码+代码说明(在代码块中任意地方输入Runtime,按住ctrl点击可调出其源码)
public class Runtime {
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
private Runtime() {}
}
1、单例模式保证了 系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
2、当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new
3、单例模式使用的场景:
标签:private 分析 volatil 创建 安全 效果 缓存 ESS 第三版
原文地址:https://www.cnblogs.com/timetellu/p/11620370.html