1,懒汉式线程不安全
package com.taotao.rfspringboot.day14;
import lombok.Synchronized;
import java.util.concurrent.SynchronousQueue;
/**
*@title: Singleton01
*@description;
*@author wangj
*@date 2021/7/19 20:23
*/
public class Singleton01 {
//懒汉式,当真正需要创建对象的时候才会创建对象
private Singleton01 singleton01;
//单例的特点,在我们的jvm里只能存在一个单例
//2无参构造函数私有化
private Singleton01(){
}
//根据该方法使用到哪里对象
public Singleton01 getSingleton01() {
if(singleton01==null){
singleton01=new Singleton01();
}
return singleton01;
}
}
懒汉式 第一次new出该对象已经赋值singleton 后面所有的线程直接获取singleton 对象不需要重复new
2,懒汉式线程安全;
3,懒汉式双重检验锁
能够保证线程的安全,只会创建单例对象的时候上锁,获取该单例对象不会上锁,效率比较高,注意 volatile 关键字避免重排序
//根据该方法使用到哪里对象
public static Singleton01 getSingleton01() {
if(singleton01==null){
synchronized(Singleton01.class){
singleton01=new Singleton01();
}
}
return singleton01;
}
懒汉式 懒加载 当我们需要对象时,才会创建对象,节约该内心
4,饿汉式,提前创建对象,优点 先天性保证安全,比较占内存。
package com.taotao.rfspringboot.day14;
/**
*@title: Singleton02
*@description; 饿汉式
*@author wangj
*@date 2021/7/19 21:42
*/
public class Singleton02 {
/**
* 饿汉式 当我们的class文件没加载 --类加载器提前创建对象
*缺陷: 如果没有使用对象的时候创建对象 占用内存
* 优点,先天性线程安全
*/
private static Singleton02 singleton=new Singleton02();
/**
* 饿汉式
*/
private Singleton02()
{
}
public Singleton02 getSingleton() {
return singleton;
}
public static void main(String[] args) {
Singleton02 singleton021=Singleton02.singleton;
Singleton02 singleton02=Singleton02.singleton;
System.out.println(singleton02==singleton021);
}
}
5,静态代码块
package com.taotao.rfspringboot.day14;
/**
* @author wangj
* @title: Singleton03
* @description;
* @date 2021/7/19 21:53
*/
public class Singleton03 {
private static Singleton03 singleton = null;
/**
* 静态代码块初始化静态对象
* 只会执行一次
*/
static {
singleton = new Singleton03();
}
public static Singleton03 getSingleton() {
return singleton;
}
public static void main(String[] args) {
Singleton03 singleton01=Singleton03.getSingleton();
Singleton03 singleton02=Singleton03.getSingleton();
System.out.println(singleton01==singleton02);
}
}
6,静态内部类
package com.taotao.rfspringboot.day14;
/**
* @author wangj
* @title: Singleton06
* @description;
* @date 2021/7/20 7:04
*/
public class Singleton06 {
private Singleton06() {
System.out.println("单例对象初始化");
}
private static Singleton06 singleton;
/**
* 静态内部类
*/
public static class Singletonolder {
private static Singleton06 singleton06 = new Singleton06();
}
public static Singleton06 getSingleton() {
return Singletonolder.singleton06;
}
public static void main(String[] args) {
Singleton06 singleton01 = Singleton06.getSingleton();
Singleton06 singleton02 = Singleton06.getSingleton();
System.out.println(singleton01==singleton02);
}
}
7,枚举实现单例; 枚举属于最安全的单例,不能被反射 序列化保证单例。
创建对象的方式:
1,直接new对象
2,采取克隆对象
3,使用反射创建对象
4序列化与反序列化
如何破解单例模式?
1,反射的机制破解单例
package com.taotao.rfspringboot.day14;
import lombok.Synchronized;
import java.util.concurrent.SynchronousQueue;
/**
*@title: Singleton01
*@description;
*@author wangj
*@date 2021/7/19 20:23
*/
public class Singleton01 {
//懒汉式,当真正需要创建对象的时候才会创建对象
private static Singleton01 singleton01;
//单例的特点,在我们的jvm里只能存在一个单例
//2无参构造函数私有化
private Singleton01() throws Exception {
System.out.println("无参构造函数");
if(singleton01!=null){
throw new Exception("该对象已经创建");
}
}
//根据该方法使用到哪里对象
public static Singleton01 getSingleton01() throws Exception {
if(singleton01==null){
synchronized(Singleton01.class){
//双重检验锁
//第一个判断 只有在new 单例对象的时候才会释放锁
//第二个判断 如果之前获取的线程new成功后无需创建
if(singleton01==null){
singleton01=new Singleton01();
}
}
}
return singleton01;
}
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//破解单例,当前对象可以new
//使用反射技术
Class<?> aClass=Class.forName("com.taotao.rfspringboot.day14.Singleton01");
//调用无参构造函数初始化
Singleton01 singleton01= (Singleton01) aClass.newInstance();
Singleton01 singleton02= (Singleton01) aClass.newInstance();
System.out.println(singleton01==singleton02);
}
}
2序列化破解单例:
序列化概念: 将对象转换成二进制的形式直接存放在本地 将该对象持久化到硬盘中-json 将对象转换成json --序列化
反序列化概念: 从硬盘中读取二进制变为对象 json 将该json转换成对象--反序列化。
网友评论