单例模式是非常常用的设计模式,不论是在无意用到还是有意为之,运用到的情况是很多的。本篇博客作为学习笔记,记录一下八种应用单例模式的方法:
- package com.DesignMode.Singleton;
-
- /**
- * 饿汉式
- * 类加载到内存后,就实例化一个单例,JVM保证线程安全
- * 简单实用,推荐使用
- * 扩展:不实例化时,经常会用到反射Class.forName(类名)
- * 唯一缺点:不管用到与否,类加载时就会完成实例化
- */
-
- public class Mgr01 {
-
- private static final Mgr01 INSTANCE = new Mgr01();
-
- private Mgr01() {
- }
-
- public static Mgr01 getInstance() {
- return INSTANCE;
- }
-
- public void m() {
- System.out.println("m");
- }
-
- public static void main(String[] args, Mgr01 m21) {
- Mgr01 m1 = Mgr01.getInstance();
- Mgr01 m2 = Mgr01.getInstance();
- System.out.println(m1 == m2);
- }
- }
- package com.DesignMode.Singleton;
-
- /**
- * 本质上与01一致
- */
- public class Mgr02 {
- private static final Mgr02 INSTANCE;
- static {
- INSTANCE = new Mgr02();
- }
-
- private Mgr02(){}
-
- public static Mgr02 getInstance(){
- return INSTANCE;
- }
-
- public void m() {
- System.out.println("m");
- }
-
- public static void main(String[] args, Mgr01 m21) {
- Mgr01 m1 = Mgr01.getInstance();
- Mgr01 m2 = Mgr01.getInstance();
- System.out.println(m1 == m2);
- }
- }
- package com.DesignMode.Singleton;
-
- /**
- * Lazy Loading
- * 懒汉式
- * 虽然达到了按需初始化的目的,但也带来了线程不安全的问题
- */
- public class Mgr03 {
- private static Mgr03 INSTANCE;
-
- private Mgr03() {
- }
-
- public static Mgr03 getInstance() {
- if (INSTANCE == null) {
- try {
- Thread.sleep(1);
- } catch (Exception e) {
- e.printStackTrace();
- }
- INSTANCE = new Mgr03();
- }
- return INSTANCE;
- }
-
- public void m() {
- System.out.println("m");
- }
-
- public static void main(String[] args) {
- for (int i = 0; i < 100; i++) {
- /*new Thread(new Runnable() {
- //Runnable针对的是只有一个匿名内部类的接口
- @Override
- public void run() {
- ...
- }
- }).start();*/
- new Thread(new Runnable() {
- public void run() {
- System.out.println(Mgr03.getInstance().hashCode());
- }
- }).start();
- }
- }
- }
- package com.DesignMode.Singleton;
-
- /**
- * Lazy Loading
- * 懒汉式
- * 虽然达到了按需初始化的目的,但也带来了线程不安全的问题
- * 可以通过synchronized锁定对象解决,但也带来效率下降的问题,此处锁定的是Manager04.Class对象
- */
- public class Mgr04 {
- private static Mgr04 INSTANCE;
-
- private Mgr04() {
- }
-
- public static synchronized Mgr04 getInstance() {
- if (INSTANCE == null) {
- try {
- Thread.sleep(1);
- } catch (Exception e) {
- e.printStackTrace();
- }
- INSTANCE = new Mgr04();
- }
- return INSTANCE;
- }
-
- public void m() {
- System.out.println("m");
- }
-
- public static void main(String[] args) {
- for (int i = 0; i < 100; i++) {
- /*new Thread(new Runnable() {
- //Runnable针对的是只有一个匿名内部类的接口
- @Override
- public void run() {
- ...
- }
- }).start();*/
- new Thread(new Runnable() {
- public void run() {
- System.out.println(Mgr04.getInstance().hashCode());
- }
- }).start();
- }
- }
- }
- package com.DesignMode.Singleton;
-
- /**
- * Lazy Loading
- * 懒汉式
- * 虽然达到了按需初始化的目的,但也带来了线程不安全的问题
- * 可以通过synchronized锁定对象解决,但也带来效率下降的问题,此处锁定的是Manager04.Class对象
- */
- public class Mgr05 {
- private static Mgr05 INSTANCE;
-
- private Mgr05() {
- }
-
- public static Mgr05 getInstance() {
- if (INSTANCE == null) {
- //妄图通过减小同步代码块的方式提高效率,但不可行
- synchronized (Mgr05.class) {
- try {
- Thread.sleep(1);
- } catch (Exception e) {
- e.printStackTrace();
- }
- INSTANCE = new Mgr05();
- }
- }
- return INSTANCE;
- }
-
- public void m() {
- System.out.println("m");
- }
-
- public static void main(String[] args) {
- for (int i = 0; i < 100; i++) {
- /*new Thread(new Runnable() {
- //Runnable针对的是只有一个匿名内部类的接口
- @Override
- public void run() {
- ...
- }
- }).start();*/
- /*new Thread(() -> {
- System.out.println(Mgr05.getInstance().hashCode());
- }).start();*/
- }
- }
- }
- package com.DesignMode.Singleton;
-
- /**
- * Lazy Loading
- * 懒汉式
- * 虽然达到了按需初始化的目的,但也带来了线程不安全的问题
- * 可以通过synchronized锁定对象解决,但也带来效率下降的问题,此处锁定的是Manager04.Class对象
- */
- public class Mgr06 {
- private static volatile Mgr06 INSTANCE;
- //JIT编译时会变成本地语言,此处可能会没有初始化INSTANCE就返回值;这里的操作不是原子性操作
-
- private Mgr06() {
- }
-
- public static Mgr06 getInstance() {
- if (INSTANCE == null) {
- //INSTANCE为空 上锁
- synchronized (Mgr06.class) {
- //双重检测锁 DCL懒汉式
- if (INSTANCE == null) {
- try {
- Thread.sleep(1);
- } catch (Exception e) {
- e.printStackTrace();
- }
- INSTANCE = new Mgr06();
- }
- }
- }
- return INSTANCE;
- }
-
- public void m() {
- System.out.println("m");
- }
-
- public static void main(String[] args) {
- for (int i = 0; i < 100; i++) {
- /*new Thread(new Runnable() {
- //Runnable针对的是只有一个匿名内部类的接口
- @Override
- public void run() {
- ...
- }
- }).start();*/
- /* new Thread(() -> {
- System.out.println(Mgr06.getInstance().hashCode());
- }).start();*/
- }
- }
- }
- package com.DesignMode.Singleton;
-
- /**
- *静态内部类方式
- * JVM保证单例
- * 加载外部类时不会加载内部类,实现懒加载
- */
- public class Mgr07 {
- private static Mgr07 INSTANCE;
-
- private Mgr07() {
- }
-
- private static class Mgr07Holder {
- private final static Mgr07 INSTANCE = new Mgr07();
- }
-
- public static Mgr07 getInstance() {
- return Mgr07Holder.INSTANCE;
- }
-
- public void m() {
- System.out.println("m");
- }
-
- public static void main(String[] args) {
- for (int i = 0; i < 100; i++) {
- /*new Thread(new Runnable() {
- //Runnable针对的是只有一个匿名内部类的接口
- @Override
- public void run() {
- ...
- }
- }).start();*/
- /*new Thread(() -> {
- System.out.println(Mgr07.getInstance().hashCode());
- }).start();*/
- }
- }
- }
- package com.DesignMode.Singleton;
-
- /**
- *不仅可以解决线程同步,还可以防止反序列化
- *
- * 枚举类没有构造方法
- */
- public enum Mgr08 {
-
- INSTANCE;
-
- public void m() {
- System.out.println("m");
- }
-
- public static void main(String[] args) {
- for (int i = 0; i < 100; i++) {
- /*new Thread(new Runnable() {
- //Runnable针对的是只有一个匿名内部类的接口
- @Override
- public void run() {
- ...
- }
- }).start();*/
- /*new Thread(() -> {
- System.out.println(Mgr08.INSTANCE.hashCode());
- }).start();*/
- }
- }
- }
实际的联系与应用中,还是要考虑到自己会用什么,理解哪种方式,哪种方式对自己的代码优化程度更高选定,玩的花不如写的实~