1.简介 一系列的操作,要么全部执行成功,要么全部不执行,不会出现执行一半的情况,是不可分割的,,这种特性被称之为原子性。
2.Java中的原子操作 1.除long和double之外的基本类型(int byte boolean short char float)的赋值操作 2.所有引用reference的赋值操作,不管是32位的机器还是64位的机器 3.java.concurrent.Atomic.*包中所有类的原子操作 4.i++不是原子性的,但可以用synchronized关键字来实现原子性
原子操作 + 原子操作 != 原子操作 简单地把原子操作组合在一起,并不能保证整体依然具有原子性。
3.单例模式 (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).单例模式总结 饿汉:简单,但是没有懒加载 懒汉:存在线程安全问题 静态内部类:可用 双重检查:面试用 枚举类:生产中推荐使用
写法简单线程安全,枚举经过反编译,本质是静态的对象可以防止反序列化破坏单例,重新创建新的对象