1.简介
一系列的操作,要么全部执行成功,要么全部不执行,不会出现执行一半的情况,是不可分割的,这种特性被称之为原子性。
2.Java中的原子操作
private int count = 0;
public void calculate(){
count++;
}
- 将count从主存中读取到线程的工作内存
- 处理器执行++操作
- 将处理器执行的结果写到工作内存
- 将线程工作内存计算的值flush到主存中
3.注意事项
- java.concurrent.Atomic.*包中所有类都具有原子性
- i++不具有原子性,但可以用synchronized关键字来实现原子性
- 原子操作 + 原子操作 != 原子操作
4.单例模式
(1).为什么使用单例模式?
当需要控制实例数目,节省系统资源的时候可以使用单例模式。保证一个类仅有一个实例,并提供一个访问它的全局访问点,这样可避免一个全局使用的类频繁地创建与销毁。
(2).使用场景
- 无状态的工具类,如日志工具类,不管是在哪里使用,只是使用它来记录日志信息,并不需要在它的实例对象上存储任何状态,此时,只需要一个实例对象即可。
- 全局信息类,如在一个类上记录网站的访问次数,但并不希望访问有的被记录在对象A上,有的被记录在B上,这时也可以让这个类成为单例。
(3).饿汉式(静态常量)(可用)
public class Singleton {
private final static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
(4).饿汉式(静态代码块)(可用)
public class Singleton {
private final static Singleton instance;
static {
instance = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
(5).懒汉式(线程不安全)(不可用)
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
//存在多个线程竞争的情况
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
(6).懒汉式(线程安全但不推荐,效率低)(可用)
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public synchronized static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
(7).懒汉式(线程不安全)(不可用)
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
//两个线程都进入的话,会导致创建两个实例的问题
synchronized (Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
}
(8).双重检查(推荐)
public class Singleton {
private volatile static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
为什么使用双重检查?
1.保障线程安全
2.弥补懒汉式线程安全但效率低的缺陷
为什么使用volatile?
1.新建对象实际上有3个步骤,创建一个空对象,调用构造函数初始化,将实例传给对象引用
2.重排序会带来空指针异常,需要防止重排序
(9).静态内部类(懒汉式))(可用)
public class Singleton {
private Singleton() {
}
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
(10).枚举单例(可用)
public enum Singleton {
INSTANCE;
public void whatever() {
}
}
(11).单例模式总结
饿汉:简单,但是没有懒加载
懒汉:存在线程安全问题
静态内部类:可用
双重检查:面试用
枚举类:生产中推荐使用
- 写法简单
- 线程安全,枚举经过反编译,本质是静态的对象
- 可以防止反序列化破坏单例,重新创建新的对象