架构设计。
--------------------------------------01-----------------------------------------------------
代码:
单例的恶汉模式:
public class SinglenObject1 {
private static final SinglenObject1 instance = new SinglenObject1();
private SinglenObject1(){
}
public static SinglenObject1 getInstance(){
return instance;
}
public static void main(String[] args) {
}
}
static用这个类就已经加载了,出现的问题就是我很长时间不使用的话就会一直存在的。
单例的懒汉模式非线程安全:
package two.chapter1;
public class SinglenObject2 {
private static SinglenObject2 instance;
private SinglenObject2(){
//empty
}
public static SinglenObject2 getInstance(){
if(null==instance){//这里会出现线程安全问题
instance = new SinglenObject2();
}
return SinglenObject2.instance;
}
}
单例的懒汉模式,线程安全:
方案1:加在这里会影响性能
双重校验锁:
优化到读不加锁。
public class SinglenObject3 {
private static SinglenObject3 instance;
private SinglenObject3(){
//empty
}
public static SinglenObject3 getInstance(){
if(null==instance){
synchronized (SinglenObject3.class){
if(null==instance){
instance = new SinglenObject3();
}
}
}
return instance;
}
}
----------------------------------------02-------------------------------------
遗留的问题:可能会引起空指针异常
假设一个哥们抢到了锁new了单例,会在堆开辟空间的。
但是此时里面的属性如构造函数并没有构造完毕。另一个哥们就拿去用了,就会空指针异常。
如何解决这个问题?
加volatile保证可见性。严格遵循happendsbefore。
volatile读的时候必须保证写全部完成。
public class SinglenObject4 {
private static volatile SinglenObject4 instance;
private SinglenObject4(){
//empty
}
public static SinglenObject4 getInstance(){
if(null==instance){
synchronized (SinglenObject4.class){
if(null==instance){
instance = new SinglenObject4();
}
}
}
return instance;
}
}
一种优雅的方式---强烈建议的,就是内部类恶汉作者推荐:
public class SinglenObject5 {
private SinglenObject5() {
}
private static class InstanceHolder {
private final static SinglenObject5 instance = new SinglenObject5();
}
public static SinglenObject5 getInstance() {
return InstanceHolder.instance;
}
}
static使用才会被加载,不使用不会被加载。
static只会初始化一次的,只有一个的。
枚举是线程安全的,构造函数只会装载一次。
枚举的方式:
public class SinglenObject6 {
private SinglenObject6() {
//empty
}
private enum Singleton{//枚举事线程安全的而且构造函数只会被装载一次的
INSTANCE;
private final SinglenObject6 instance;
Singleton(){
instance = new SinglenObject6();
}
public SinglenObject6 getInstance(){
return instance;
}
}
public static SinglenObject6 getInstance(){
return Singleton.INSTANCE.getInstance();
}
public static void main(String[] args) {
IntStream.rangeClosed(1,100).forEach(i->new Thread(String.valueOf(i)){
@Override
public void run(){
System.out.println(SinglenObject6.getInstance());
}
}.start());
}
}
枚举的构造函数是私有的只会被装载一次。枚举类私有。
定义INSTANCD的时候,构造函数就已经创建了。
-----------------------------------03-------------------------------------
问题的补充:单例为什么加volatile:https://www.cnblogs.com/tiancai/p/9927948.html