单例模式-创建型
单例分为懒汉式和饿汉式
简单代码块
懒汉式
个人解释懒加载生成对象,即用到的时候才去实例化
单线程
public class Lazy {
private static Lazy l;
private Lazy() {
}
public static Lazy getH(){
if(l==null){
l=new Lazy();
}
return l;
}
}
//懒汉式 双检锁 多线程
public class SingleTest {
private static boolean key = false;
//volatile指令实现有序性,防止指令重排序,否则在双检锁中获取到null
//eg:第一个线程进入singleTest=new SingleTest(); 但是顺序是先引用赋值未初始化
//第二个线程进入发现第一个判断singleTest!=null 返回未初始化的singleTest
private static volatile SingleTest singleTest;
private SingleTest(){
synchronized (SingleTest.class){
if (key==false){
key=true;
}
else{
throw new RuntimeException("不要试图使用反射破坏异常");
}
}
System.out.println(Thread.currentThread().getName()+" ok");
}
public static SingleTest instance(){
if(singleTest==null){
synchronized (SingleTest.class){
if(singleTest==null){
singleTest=new SingleTest();
}
}
}
return singleTest;
}
public static void main(String[] args) {
try {
//Java中有反射
// LazyMan instance = LazyMan.getInstance();
Field key = SingleTest.class.getDeclaredField("key");
key.setAccessible(true);
Constructor<SingleTest> declaredConstructor = SingleTest.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true); //无视了私有的构造器
SingleTest instance1 = SingleTest.instance();
key.set(instance1,false);
SingleTest lazyMan1 = declaredConstructor.newInstance();
SingleTest instance = declaredConstructor.newInstance();
System.out.println(instance);
System.out.println(lazyMan1);
System.out.println(instance == lazyMan1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
饿汉式
普通饿汉式
public class Hungry {
private static final Hungry h=new Hungry();
private Hungry() {
}
public static Hungry getH(){
return h;
}
}
静态内部类 天生线程安全
注意使用ObejectOutputStream oos序列化前后导致对象不是同一地址,可以重写readResolve()方法解决
//静态内部类
public class SingleStatic {
private static class Inner{
private static final SingleStatic singleStatic=new SingleStatic();
}
private SingleStatic(){
}
public static SingleStatic instance(){
return Inner.singleStatic;
}
}
Enum枚举类型 天生线程安全 序列化也能包装同一对象
public enum EnumSingleTest {
INSTANCE;
int a;
public EnumSingleTest instance() {
return INSTANCE;
}
public static void main(String[] args) {
try {
Constructor<EnumSingleTest> declaredConstructor = EnumSingleTest.class.getDeclaredConstructor(String.class,int.class);
declaredConstructor.setAccessible(true);
EnumSingleTest enumSingleTest = declaredConstructor.newInstance();
System.out.println(enumSingleTest);
} catch (Exception e) {
e.printStackTrace();
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现