单例模式

饿汉式

  1. /**
  2. * 饿汉式
  3. * 类加载到内存后,就实例化一个单例,JVM保证线程安全
  4. * 简单实用,推荐使用!
  5. * 唯一缺点:不管用到与否,类装载时就完成实例化
  6. * Class.forName("")
  7. * (话说你不用的,你装载它干啥)
  8. */
  9. public class Mgr01 {
  10. private static final Mgr01 INSTANCE = new Mgr01();
  11. private Mgr01() {};
  12. public static Mgr01 getInstance() {
  13. return INSTANCE;
  14. }
  15. public void m() {
  16. System.out.println("m");
  17. }
  18. public static void main(String[] args) {
  19. Mgr01 m1 = Mgr01.getInstance();
  20. Mgr01 m2 = Mgr01.getInstance();
  21. System.out.println(m1 == m2);
  22. }
  23. }

懒汉式

  1. /**
  2. * lazy loading
  3. * 也称懒汉式
  4. * 虽然达到了按需初始化的目的,但却带来线程不安全的问题
  5. */
  6. public class Mgr03 {
  7. private static Mgr03 INSTANCE;
  8. private Mgr03() {
  9. }
  10. public static Mgr03 getInstance() {
  11. if (INSTANCE == null) {
  12. try {
  13. Thread.sleep(1);
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. }
  17. INSTANCE = new Mgr03();
  18. }
  19. return INSTANCE;
  20. }
  21. public void m() {
  22. System.out.println("m");
  23. }
  24. public static void main(String[] args) {
  25. for(int i=0; i<100; i++) {
  26. new Thread(()->
  27. System.out.println(Mgr03.getInstance().hashCode())
  28. ).start();
  29. }
  30. }
  31. }
  1. /**
  2. * lazy loading
  3. * 也称懒汉式
  4. * 虽然达到了按需初始化的目的,但却带来线程不安全的问题
  5. * 可以通过synchronized解决,但也带来效率下降
  6. */
  7. public class Mgr04 {
  8. private static Mgr04 INSTANCE;
  9. private Mgr04() {
  10. }
  11. public static synchronized Mgr04 getInstance() {
  12. if (INSTANCE == null) {
  13. try {
  14. Thread.sleep(1);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. INSTANCE = new Mgr04();
  19. }
  20. return INSTANCE;
  21. }
  22. public void m() {
  23. System.out.println("m");
  24. }
  25. public static void main(String[] args) {
  26. for(int i=0; i<100; i++) {
  27. new Thread(()->{
  28. System.out.println(Mgr04.getInstance().hashCode());
  29. }).start();
  30. }
  31. }
  32. }
  1. /**
  2. * lazy loading
  3. * 也称懒汉式
  4. * 虽然达到了按需初始化的目的,但却带来线程不安全的问题
  5. * 可以通过synchronized解决,但也带来效率下降
  6. */
  7. public class Mgr05 {
  8. private static Mgr05 INSTANCE;
  9. private Mgr05() {
  10. }
  11. public static Mgr05 getInstance() {
  12. if (INSTANCE == null) {
  13. //妄图通过减小同步代码块的方式提高效率,
  14. //然后不可行--不可行的原因是instance=new SingletonDemo()
  15. //的几个步骤可能发生指令重排
  16. synchronized (Mgr05.class) {
  17. try {
  18. Thread.sleep(1);
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. }
  22. INSTANCE = new Mgr05();
  23. }
  24. }
  25. return INSTANCE;
  26. }
  27. public void m() {
  28. System.out.println("m");
  29. }
  30. public static void main(String[] args) {
  31. for(int i=0; i<100; i++) {
  32. new Thread(()->{
  33. System.out.println(Mgr05.getInstance().hashCode());
  34. }).start();
  35. }
  36. }
  37. }
  1. /**
  2. * lazy loading
  3. * 也称懒汉式
  4. * 虽然达到了按需初始化的目的,但却带来线程不安全的问题
  5. * 可以通过synchronized解决,但也带来效率下降
  6. */
  7. public class Mgr06 {
  8. private static volatile Mgr06 INSTANCE; //JIT
  9. private Mgr06() {
  10. }
  11. public static Mgr06 getInstance() {
  12. if (INSTANCE == null) {
  13. //双重检查
  14. synchronized (Mgr06.class) {
  15. if(INSTANCE == null) {
  16. try {
  17. Thread.sleep(1);
  18. } catch (InterruptedException e) {
  19. e.printStackTrace();
  20. }
  21. INSTANCE = new Mgr06();
  22. }
  23. }
  24. }
  25. return INSTANCE;
  26. }
  27. public void m() {
  28. System.out.println("m");
  29. }
  30. public static void main(String[] args) {
  31. for(int i=0; i<100; i++) {
  32. new Thread(()->{
  33. System.out.println(Mgr06.getInstance().hashCode());
  34. }).start();
  35. }
  36. }
  37. }

静态内部类方式

  1. /**
  2. * 静态内部类方式
  3. * JVM保证单例
  4. * 加载外部类时不会加载内部类,这样可以实现懒加载
  5. */
  6. public class Mgr07 {
  7. private Mgr07() {
  8. }
  9. private static class Mgr07Holder {
  10. private final static Mgr07 INSTANCE = new Mgr07();
  11. }
  12. public static Mgr07 getInstance() {
  13. return Mgr07Holder.INSTANCE;
  14. }
  15. public void m() {
  16. System.out.println("m");
  17. }
  18. public static void main(String[] args) {
  19. for(int i=0; i<100; i++) {
  20. new Thread(()->{
  21. System.out.println(Mgr07.getInstance().hashCode());
  22. }).start();
  23. }
  24. }
  25. }

enum枚举方式

  1. /**
  2. * 不仅可以解决线程同步,还可以防止反序列化。
  3. */
  4. public enum Mgr08 {
  5. INSTANCE;
  6. public void m() {}
  7. public static void main(String[] args) {
  8. for(int i=0; i<100; i++) {
  9. new Thread(()->{
  10. System.out.println(Mgr08.INSTANCE.hashCode());
  11. }).start();
  12. }
  13. }
  14. }

单例模式反序列化漏洞测试
  1. public class DeserializationTest {
  2. public static void main(String[] args) throws Exception {
  3. Mgr01 s1 = Mgr01.getInstance();
  4. Mgr01 s2 = Mgr01.getInstance();
  5. System.out.println(s1);
  6. System.out.println(s2);
  7. Class.forName("singleton.Mgr01");
  8. /**
  9. * 单例模式反射漏洞測試
  10. */
  11. Class<?> clazz = Class.forName("singleton.Mgr01");
  12. Constructor<Mgr01> c = (Constructor<Mgr01>) clazz.getDeclaredConstructor(null);
  13. c.setAccessible(true);
  14. Mgr01 s3 = c.newInstance();
  15. Mgr01 s4 = c.newInstance();
  16. System.out.println(s3);
  17. System.out.println(s4);
  18. }
  19. }
  1. singleton.Mgr01@17e1886
  2. singleton.Mgr01@17e1886
  3. singleton.Mgr01@d1a2f1
  4. singleton.Mgr01@10e140b