单例模式与多线程
单例模式就是全局唯一但是所有程序都可以使用的对象
写单例模式步骤:
1.将构造函数设置为私有的
2.创建一个静态的类变量
3.提供获取单例的方法
立即加载/饿汉模式
- /**
- * user:ypc;
- * date:2021-06-13;
- * time: 21:02;
- */
- //饿汉方式实现单例模式
- public class Singleton {
- //1.将构造函数设置为私有的,不然外部可以创建
- private Singleton(){
- }
- //2.创建静态的类变量(让第三步的方法进行返回)
- private static Singleton singleton = new Singleton();
- //给外部接口提供的获取单例的方法
- public static Singleton getInstance(){
- return singleton;
- }
- }
测试饿汉的单例模式
- //测试饿汉方式实现的单例模式,创建两个线程,看是不是得到了一个实列对象,如果为true就说明饿汉的单例模式没有问题
- static Singleton singleton1 = null;
- static Singleton singleton2 = null;
- public static void main(String[] args) throws InterruptedException {
- Thread thread1 = new Thread(() -> {
- singleton1 = Singleton.getInstance();
- });
- Thread thread2 = new Thread(() -> {
- singleton2 = Singleton.getInstance();
- });
- thread1.start();
- thread2.start();
- thread1.join();
- thread2.join();
- System.out.println(singleton1 == singleton2);
- }
延时加载/懒汉模式
不会随着程序的启动而启动,而是等到有人调用它的时候,它才会初始化
- /**
- * user:ypc;
- * date:2021-06-13;
- * time: 21:22;
- */
- //懒汉方式实现单例模式
- public class Singleton2 {
- static class Singleton {
- //1.设置私有的构造函数
- private Singleton() {
- }
- //2.提供一个私有的静态变量
- private static Singleton singleton = null;
- //3.提供给外部调用,返回一个单例对象给外部
- public static Singleton getInstance() {
- if (singleton == null) {
- singleton = new Singleton();
- }
- return singleton;
- }
- }
- }
那么这样写有什么问题呢?我们来看看多线程情况下的懒汉方式实现单例模式:
- /**
- * user:ypc;
- * date:2021-06-13;
- * time: 21:22;
- */
- //懒汉方式实现单例模式
- public class Singleton2 {
- static class Singleton {
- //1.设置私有的构造函数
- private Singleton() {
- }
- //2.提供一个私有的静态变量
- private static Singleton singleton = null;
- //3.提供给外部调用,返回一个单例对象给外部
- public static Singleton getInstance() throws InterruptedException {
- if (singleton == null) {
- Thread.sleep(100);
- singleton = new Singleton();
- }
- return singleton;
- }
- }
- static Singleton singleton1 = null;
- static Singleton singleton2 = null;
- public static void main(String[] args) throws InterruptedException {
- Thread thread1 = new Thread(() -> {
- try {
- singleton1 = Singleton.getInstance();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- });
- Thread thread2 = new Thread(() -> {
- try {
- singleton2 = Singleton.getInstance();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- });
- thread1.start();
- thread2.start();
- thread1.join();
- thread2.join();
- System.out.println(singleton1 == singleton2);
- }
- }
结果:
所以发生了线程不安全的问题
那么要如何更改呢?
加锁: