彻底搞懂Java多线程(五)

时间:2022-10-07 22:36:44

单例模式与多线程

单例模式就是全局唯一但是所有程序都可以使用的对象

写单例模式步骤:

1.将构造函数设置为私有的

2.创建一个静态的类变量

3.提供获取单例的方法

立即加载/饿汉模式

  1. /**
  2. * user:ypc;
  3. * date:2021-06-13;
  4. * time: 21:02;
  5. */
  6. //饿汉方式实现单例模式
  7. public class Singleton {
  8. //1.将构造函数设置为私有的,不然外部可以创建
  9. private Singleton(){
  10. }
  11. //2.创建静态的类变量(让第三步的方法进行返回)
  12. private static Singleton singleton = new Singleton();
  13. //给外部接口提供的获取单例的方法
  14. public static Singleton getInstance(){
  15. return singleton;
  16. }
  17. }

测试饿汉的单例模式

  1. //测试饿汉方式实现的单例模式,创建两个线程,看是不是得到了一个实列对象,如果为true就说明饿汉的单例模式没有问题
  2. static Singleton singleton1 = null;
  3. static Singleton singleton2 = null;
  4. public static void main(String[] args) throws InterruptedException {
  5. Thread thread1 = new Thread(() -> {
  6. singleton1 = Singleton.getInstance();
  7. });
  8. Thread thread2 = new Thread(() -> {
  9. singleton2 = Singleton.getInstance();
  10. });
  11. thread1.start();
  12. thread2.start();
  13. thread1.join();
  14. thread2.join();
  15. System.out.println(singleton1 == singleton2);
  16. }

彻底搞懂Java多线程(五)

延时加载/懒汉模式

不会随着程序的启动而启动,而是等到有人调用它的时候,它才会初始化

  1. /**
  2. * user:ypc;
  3. * date:2021-06-13;
  4. * time: 21:22;
  5. */
  6. //懒汉方式实现单例模式
  7. public class Singleton2 {
  8. static class Singleton {
  9. //1.设置私有的构造函数
  10. private Singleton() {
  11. }
  12. //2.提供一个私有的静态变量
  13. private static Singleton singleton = null;
  14. //3.提供给外部调用,返回一个单例对象给外部
  15. public static Singleton getInstance() {
  16. if (singleton == null) {
  17. singleton = new Singleton();
  18. }
  19. return singleton;
  20. }
  21. }
  22. }

那么这样写有什么问题呢?我们来看看多线程情况下的懒汉方式实现单例模式:

  1. /**
  2. * user:ypc;
  3. * date:2021-06-13;
  4. * time: 21:22;
  5. */
  6. //懒汉方式实现单例模式
  7. public class Singleton2 {
  8. static class Singleton {
  9. //1.设置私有的构造函数
  10. private Singleton() {
  11. }
  12. //2.提供一个私有的静态变量
  13. private static Singleton singleton = null;
  14. //3.提供给外部调用,返回一个单例对象给外部
  15. public static Singleton getInstance() throws InterruptedException {
  16. if (singleton == null) {
  17. Thread.sleep(100);
  18. singleton = new Singleton();
  19. }
  20. return singleton;
  21. }
  22. }
  23. static Singleton singleton1 = null;
  24. static Singleton singleton2 = null;
  25. public static void main(String[] args) throws InterruptedException {
  26. Thread thread1 = new Thread(() -> {
  27. try {
  28. singleton1 = Singleton.getInstance();
  29. } catch (InterruptedException e) {
  30. e.printStackTrace();
  31. }
  32. });
  33. Thread thread2 = new Thread(() -> {
  34. try {
  35. singleton2 = Singleton.getInstance();
  36. } catch (InterruptedException e) {
  37. e.printStackTrace();
  38. }
  39. });
  40. thread1.start();
  41. thread2.start();
  42. thread1.join();
  43. thread2.join();
  44. System.out.println(singleton1 == singleton2);
  45. }
  46. }

结果:

彻底搞懂Java多线程(五)

所以发生了线程不安全的问题

那么要如何更改呢?

加锁: