Java多线程_单例模式与多线程

本文深入探讨了单例模式的不同实现方式,包括立即加载(饿汉模式)、延迟加载(懒汉模式),并介绍了如何通过静态内置类、DCL双检查锁机制等解决线程安全问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

立即加载|饿汉模式

什么是立即加载?立即加载就是使用类的时候已经将对象创建完毕,常见的实现办法就是直接new实例化

package multiply.com.test;
public class Run {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();
        t1.start();
        t2.start();
        t3.start();
    }
}
package multiply.com.test;
public class MyThread extends Thread {
    @Override
    public void run() {
        super.run();
        System.out.println(MyObject.getInstance().hashCode());
    }
}
package multiply.com.test;
public class MyObject {
    private static MyObject object = new MyObject();
    public static MyObject getInstance() {
        return object;
    }
}

1213024637
1213024637
1213024637
控制台打印的hashCode是同一个值,说明对象是同一个,也就实现了立即加载型单例设计模式。

延迟加载|懒汉模式

什么是延迟加载?延迟加载就是在调用get()方法时实例才被创建,常见的实现办法就是在get()方法中进行new实例化。

package multiply.com.test;
public class MyObject {
    private static MyObject object;
    private MyObject()
    {
    }
    public static MyObject getInstance() {
        if (null == object) {
            try {
                Thread.sleep(2000);
                object = new MyObject();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return object;
    }
}
package multiply.com.test;
public class MyThread extends Thread {
    @Override
    public void run() {
        super.run();
        System.out.println(MyObject.getInstance().hashCode());
    }
}
package multiply.com.test;
public class Run {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();
        t1.start();
        t2.start();
        t3.start();
    }
}

106990145
355386388
1213024637
控制台打印出了3种hashCode,说明创建出了3个对象,并不是单例的,这就是“错误的单例模式”。

( 1 )声明synchronized关键字
既然多个线程可以同时进入getInstance()方法,那么只需要对getInstance()方法声明synchronized关键字即可。
在这里插入图片描述
同步代码块可以针对某些重要的代码进行单独的同步,而其他的代码则不需要同步。
在这里插入图片描述
此方法使同步synchronized语句块,只对实例化对象的关键代码进行同步,从语句的结构上来讲,运行的效率的确得到了提升。但如果是遇到多线程的情况下还是无法解决得到同一个实例对象的结果。到底如何解决“懒汉模式”遇到多线程的情况呢?

(4)使用DCL双检查锁机制
在最后的步骤中,使用的是DCL双检查锁机制来实现多线程环境中的延迟加载单例设计模式。

package multiply.com.test;
public class Run {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();
        t1.start();
        t2.start();
        t3.start();
    }
}
package multiply.com.test;
public class MyThread extends Thread {
    @Override
    public void run() {
        super.run();
        System.out.println(MyObject.getInstance().hashCode());
    }
}
package multiply.com.test;
public class MyObject {
    private static volatile MyObject object;
    public static MyObject getInstance() {
        if (null == object) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (MyObject.class) {
                if (null == object) {
                    object = new MyObject();
                }
            }
        }
        return object;
    }
}

2042504460
2042504460
2042504460
使用双重检查锁功能,成功地解决了“懒汉模式”遇到多线程的问题。DCL 也是大多数多线程结合单例模式使用的解决方案。

使用静态内置类实现单例模式

package multiply.com.test;
public class Run {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();
        t1.start();
        t2.start();
        t3.start();
    }
}
package multiply.com.test;
public class MyThread extends Thread {
    @Override
    public void run() {
        super.run();
        System.out.println(MyObject.getInstance().hashCode());
    }
}
package multiply.com.test;
public class MyObject {
    private static class MyObjectHandler {
        private static MyObject object = new MyObject();
    }
    public static MyObject getInstance() {
        return MyObjectHandler.object;
    }
}

1282593964
1282593964
1282593964

序列化与反序列化的单例模式

静态内置类可以达到线程安全问题,但如果遇到序列化对象时,使用默认的方式运行得到的结果还是多例的。
在这里插入图片描述

使用static代码块实现单例模式

在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

身影王座

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值