单例设计模式 silgleton
饿汉式
不管加载与否 都创建
/**
* 饿汉式 不管用不用都创建
*/
public class Singleton1 {
//写法1
private static final Singleton1 INSTANCE=new Singleton1();
//写法2 静态块加载
/**
* private static Singleton1 INSTANCE;
* static {
* INSTANCE=new Singleton1();
* }
*/
private Singleton1(){
}
public Singleton1 newInstance(){
return INSTANCE;
}
}
懒汉式
只有在用到时才加载,但是在多线程的情况下会出现对象不一样的问题
/**
* 懒汉式 只有用到才创建,多线程下会有问题
*/
public class Singleton1 {
private static Singleton1 INSTANCE;
private Singleton1(){
}
public Singleton1 newInstance(){
if(INSTANCE==null){
INSTANCE=new Singleton1();
}
return INSTANCE;
}
}
同步方法锁 synchronized
方法锁控制,读写效率低
/**
* 方法锁控制 读写操作都上锁 效率低
*/
public class Singleton1 {
private static Singleton1 INSTANCE;
private Singleton1(){
}
public synchronized Singleton1 newInstance(){
if(INSTANCE==null){
INSTANCE=new Singleton1();
}
return INSTANCE;
}
}
同步代码块锁
程序块锁1 —多线程下会出现问题
/**
* 同步代码锁控制 如果第一个线程执行很慢执行到 ==null语句 而另一个线程已经执行完成并释放了锁
* 此时会造成对象不是单例的问题
*/
public class Singleton1 {
private static Singleton1 INSTANCE;
private Singleton1(){
}
public Singleton1 newInstance(){
if(INSTANCE==null){
synchronized(Singleton1.class) {
INSTANCE = new Singleton1();
}
}
return INSTANCE;
}
}
程序块锁2----效率和同步方法锁一样低
/**
* 同步代码锁控制 全部上锁 效率和方法锁一样很低
*/
public class Singleton1 {
private static Singleton1 INSTANCE;
private Singleton1(){
}
public Singleton1 newInstance(){
synchronized(Singleton1.class) {
if(INSTANCE==null){
INSTANCE = new Singleton1();
}
}
return INSTANCE;
}
}
最完美的懒汉式
同步代码块+俩次 ==null判断
/**
* 最完美 俩次==null判断
*/
public class Singleton1 {
//需要加上volatile,为了防止指令重排
private static volatile Singleton1 INSTANCE;
private Singleton1(){
}
public Singleton1 newInstance(){
if(INSTANCE==null) {
synchronized (Singleton1.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton1();
}
}
}
return INSTANCE;
}
}
静态内部类
静态内部类在外部类被加载的时候,是不会被加载的,只有在调用的时候才会被加载
并且jvm在加载class时只加载一次,所以多线程下是单例
/**
* 最完美 使用静态内部类
* 静态内部类在外部类被加载的时候,是不会被加载的,只有在调用的时候才会被加载
* 并且jvm在加载class时只加载一次,所以多线程下是单例
*/
public class Singleton1 {
private Singleton1(){
}
public static class Singleton1Holder{
private static final Singleton1 INSTANCE=new Singleton1();
}
public Singleton1 newInstance(){
return Singleton1Holder.INSTANCE;
}
}
使用enum 最最最完美
枚举类没有构造方法(所以不能被反序列化)
枚举类在第一次被真正用到的时候,才会被虚拟机加载并初始化,且这个加载过程是线程安全的
/**
* 枚举单例
* 不仅可以解决线程同步 而且可以解决反序列化
*/
public enum Singleton1 {
INSTANCE;
}