设计模式: 单例

0. ref

  1. 最好的设计模式 总结 博客

https://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html

  1. hensen 设计模式速攻

https://blog.youkuaiyun.com/qq_30379689/article/details/77349786

1. lazy 线程不安全的

public class Singleton {
	Singleton s;
	private Singleton(){}; // rem
	public static Singleton getInstance () {
		if (s == null) {
			s = new Singleton();
		}
		return s; // rem
	}
}

2. lazy 线程安全的

public class Singleton {
	Singleton s;
	private Singleton(){}; // rem
	public static Singleton getInstance () {
		synchronize(Singleton.class) {
			if (s == null) {
				s = new Singleton();
			}
			return s; // 不要再这里返回吧
		}
	}
}

改正

public class Singleton {
	Singleton s;
	private Singleton(){}; // rem
	public static Singleton getInstance () {
		synchronize(Singleton.class) {
			if (s == null) {
				s = new Singleton();
			}
		}
		return s; // rem 在这里返回
	}
}

fix: 前面两个都没有加上的private static 前缀

应该让所有类实例都持有同一个单例对象(尽管我们的类实例的构造器是private的,但是也要遵循封闭式原则,如下:

Singleton s; 
改为:
private static Singleton s = null;

这样的话,第二个多线程安全的单例就是:

public class Singleton {
	private static Singleton s = null;
	private Singleton(){}; // rem
	public static Singleton getInstance () {
		synchronize(Singleton.class) {
			if (s == null) {
				s = new Singleton();
			}
		}
		return s; // 推荐 在这里返回
	}
}

3. lazy 双重校验锁

第二个方式的加锁太重量级了,也就是说,锁太大了,只要访问了getInstance()这个方法,就会进行加锁,就是会发生创建代码中的临界区,这个加锁的动作,会消耗一定的cpu指令周期,以至于程序整体的效率会因此(经常加锁)而降低。

于是,方案3来了: 就是在单例不存在的时候,才去新建,而且新建单例的时候,保持多线程安全。

代码如下:

public class Singleton {
	private static Singleton s = null;
	private Singleton(){};
	public static Singleton getInstance () {
		if (s == null) { // here 划重点!单例不存在的时候
			synchronize(Singleton.class) {// 而且新建单例的时候,加锁保持多线程安全
				if (s == null) {
					s = new Singleton();//才去新建
				}
			}
		}
		return s; // 推荐 在这里返回
	}
}

这个方式3 照他说的,

还是有点危险

在Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton(); 这个语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,然后(1)直接赋值给instance成员,然后再(2)去初始化这个Singleton实例,但是万一一个其他的线程B 在2还没做的时候进来,(eg 1.5)的时候,这样就可能出错了

我们以A、B两个线程为例:

  1. A、B线程同时进入了第一个if判断

  2. A首先进入synchronized块,由于instance为null,所以它执行instance = new Singleton();

  3. 由于JVM内部的优化机制,JVM先画出了一些分配给Singleton实例的空白内存,并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。

  4. B进入synchronized块,由于instance此时不是null,因此它马上离开了synchronized块并将结果返回给调用该方法的程序。

  5. 此时B线程打算使用Singleton实例,却发现它没有被初始化,于是错误发生了。

4. eager, 加了volatile 的lazy 懒汉?

非也,在一开始声明的时候就初始化, 这是有多饿

public class Singleton {
	//在一开始声明的时候就初始化
	private volatile static Singleton s = new Singleton();
	private Singleton(){};
	public static Singleton getInstance() {
		return s;
	}
}

5. 静态内部类,用了JVM内部的机制

用了 jvm 的特性:

JVM内部的机制能够保证: 当一个类被加载的时候,这个类的加载过程是线程互斥的

class OutterSingleton {
    private OutterSingleton() {}
    private static class SingletonFactory{
        private static OutterSingleton s = new OutterSingleton();
    }

    public static OutterSingleton getInstance() {
        return SingletonFactory.s;// 你可以访问内部类的private 
    }
}
public class singletonTestInnerPrivate{
    public static void main(String[] args) {
        OutterSingleton m = OutterSingleton.getInstance();
        System.out.println("done");
    }
}

6. 枚举

// version 1.6 
public enum EnumSingleton {
    INSTANCE;  

    public void doSomeThing() {  

    }  
}

这是利用了1.6 的新特性,请todo

资源下载链接为: https://pan.quark.cn/s/1bfadf00ae14 “STC片机电压测量”是一个以STC系列片机为基础的电压检测应用案,它涵盖了硬件电路设计、软件编程以及数据处理等核心知识点。STC片机凭借其低功耗、高性价比丰富的I/O接口,在电子工程领域得到了广泛应用。 STC是Specialized Technology Corporation的缩写,该公司的片机基于8051内核,具备内部振荡器、高速运算能力、ISP(在系统编程)IAP(在应用编程)功能,非常适合用于各种嵌入式控制系统。 在源代码方面,“浅雪”风格的代码通常简洁易懂,非常适合初学者学习。其中,“main.c”文件是程序的入口,包含了电压测量的核心逻辑;“STARTUP.A51”是启动代码,负责初始化片机的硬件环境;“电压测量_uvopt.bak”“电压测量_uvproj.bak”可能是Keil编译器的配置文件备份,用于设置编译选项项目配置。 对于3S锂电池电压测量,3S锂电池由三节锂离子电池串联而成,标称电压为11.1V。测量时需要考虑电池的串联特性,通过分压电路将高电压转换为片机可接受的范围,并实时监控,防止过充或过放,以确保电池的安全寿命。 在电压测量电路设计中,“电压测量.lnp”文件可能包含电路布局信息,而“.hex”文件是编译后的机器码,用于烧录到片机中。电路中通常会使用ADC(模拟数字转换器)将模拟电压信号转换为数字信号供片机处理。 在软件编程方面,“StringData.h”文件可能包含程序中使用的字符串常量数据结构定义。处理电压数据时,可能涉及浮点数运算,需要了解STC片机对浮点数的支持情况,以及如何高效地存储显示电压值。 用户界面方面,“电压测量.uvgui.kidd”可能是用户界面的配置文件,用于显示测量结果。在嵌入式系统中,用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值