看本篇博客需要对JVM有一点点了解,当然可以在不懂的地方自己查也是可以的。另外如果有错误的地方,请评论区指正^^^
1、单例模式(Singleton Pattern)单例模式呢,顾名思义,在一个JVM运行实例中,某个类只有这么一个对象,无论在哪里获取该类的对象,得到的都是同一个对象,我们称这样的类的设计模式属于单例模式。
单例模式分类有两种:
饿汉式:在类的加载(类的加载又分为主动使用和被动使用,一般被动使用不会触发clinit方法)时一般是在
懒汉式:顾名思义,听过懒加载的可能都知道懒的意思,就是用的时候再加载,放在这也就是第一次使用该单例对象的时候会被加载。
1.1、饿汉式--(静态变量/静态代码块方式)--代码块里有评价public class Test_01_StaticVar {
//将构造器私有
private Test_01_StaticVar(){}
//定义一个私有的静态变量
private static Test_01_StaticVar instance = new Test_01_StaticVar();
//提供获取单例对象的静态方法
public static Test_01_StaticVar getInstance(){
return instance;
}
}
或是这样子写,其实在字节码中都体现在方法中
public class Test_01_StaticVar {
//将构造器私有
private Test_01_StaticVar(){}
//定义一个私有的静态变量
private static Test_01_StaticVar instance = null;
static {
instance = new Test_01_StaticVar();
}
public static Test_01_StaticVar getInstance(){
return instance;
}
}
//这种方式会在类加载时直接被创建,有关的评价说是因为可能被加载之后一直不使用造成内存浪费,
//很多人包括我也很纳闷,不主动使用怎么会导致类的加载。
1.2、懒汉式--基础版本
public class Test_02_Lazy01 {
private Test_02_Lazy01(){}
private static Test_02_Lazy01 instance;
public static Test_02_Lazy01 getInstance(){
if(instance == null){
instance = new Test_02_Lazy01();
}
return instance;
}
}
//缺点就是在并发获取的情况下会造成不是单例的情况。
//例如但不限于以下一种情况:假设instance是null,当A线程指向到判断语句进入if开始new对象之前此线程的调度时间结束开始调度其他线程,
//另一个线程B在这段时间也执行了这个if语句并且也成功的进入if代码块内,之后就会导致两次创建这个对象。造成的结果就不符合单例这一条件。
一种解决方式如下:
public class Test_02_Lazy01 {
private Test_02_Lazy01(){}
private static Test_02_Lazy01 instance;
public static synchronized Test_02_Lazy01 getInstance(){ <---不同点在这行
if(instance == null){
instance = new Test_02_Lazy01();
}
return instance;
}
}
//synchronized写方法头上的缺点是性能不高,获取该对象就会获取锁。大多数是只需要读就可以的。只有第一次创建时获取锁才有意义
1.3、懒汉式--升级版本--双重检查锁
public class Test_02_Lazy02 {
private Test_02_Lazy02(){}
private static Test_02_Lazy02 instance;
public static Test_02_Lazy02 getInstance(){
if(instance == null){
synchronized (Test_02_Lazy02.class) {
if(instance == null)
instance = new Test_02_Lazy02();
}
}
return instance;
}
}
//是不是感觉这样就很完美,其实不然
//还是有问题,可能会空指针异常,因为虚拟机优化的问题指令序列会重排(据说学过并发编程的应该知道。博主暂时没学)
睁大眼睛了,最终版本如下:
public class Test_02_Lazy02 {
private Test_02_Lazy02(){}
private static volatile Test_02_Lazy02 instance;
public static Test_02_Lazy02 getInstance(){
if(instance == null){
synchronized (Test_02_Lazy02.class) {
if(instance == null)
instance = new Test_02_Lazy02();
}
}
return instance;
}
}
volatile 关键字可以保证可见性和有序性。
1.4、懒汉式--静态内部类方式静态内部类在主类加载的时候是不会被加载的,利用这个特点我们可以这样做:
public class Test_02_LazyInnerClass {
private Test_02_LazyInnerClass(){}
private static class TestHolder{
private static final Test_02_LazyInnerClass INSTANCE = new Test_02_LazyInnerClass();
}
public static Test_02_LazyInnerClass getInstance(){
return TestHolder.INSTANCE;
}
}
//这是比较推荐的方式,很多开源项目在用这种方式
enum Test_05_HangryEnum {
INSTANCE;
public void testmethod1(){
System.out.println("我是实例方法一");
}
public void testmethod2(){
System.out.println("我是实例方法二");
}
public Test_05_HangryEnum getInstance(){
return INSTANCE;
}
}
//有关枚举等价的类形式,请自行查阅
未完结。。



