Java 多线程学习三(单例模式与多线程)

本文探讨了Java中的单例模式,解释了其确保类只有一个实例并提供全局访问点的原理。讨论了饿汉式和懒汉式的实现方式,以及它们在线程安全和性能上的差异。此外,还提到了同步方法锁、同步代码块和双重检查等实现单例时考虑的线程安全策略。单例模式常见于数据库连接池和线程池等资源共享场景。

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

一、什么是单例模式?

单例模式(Singleton)是一种比较常用的设计模式,在应用场景中,单例模式的类的对象有且只有一个。例如打印机只有一台,避免两个任务同时下发到打印机中,通信端口只有一个,避免多个请求同时调用通信端口,这样的情况下,单例模式是非常有用的。

单例模式就是确保一个类只有一个实例,并提供一个访问它的全局访问点。

类图 :

  • Singleton() 构造方法私有化:防止外部初始化,由类本身进行实例化
  • Singleton singleton 指向自己实例的私有静态引用
  • getInstance() 以自己实例为返回值的静态的公有方法:对外提供获取实例的方法

二、模式详解

1、饿汉式:在类加载初始化的时候就主动创建实例,立即加载

package SingletonDemo;

//饿汉式
public class Singleton1 {
    private Singleton1() {
    }

    //立即加载
    private static Singleton1 singleton1 = new Singleton1();

    public static Singleton1 getInstance() {
        return singleton1;
    }
}

2、懒汉式:等真正使用的时候再去创建实例,延迟实例化,不用时不主动创建实例

package SingletonDemo;

//懒汉式
public class Singleton2 {
    private Singleton2() {
    }

    //类加载时不主动创建实例
    private static Singleton2 singleton2;

    //在要获取时候,真正使用时
    public static Singleton2 getInstance() {
        if (singleton2 == null) {
            //再创建单例
            singleton2 = new Singleton2();
        }
        return singleton2;
    }
}

对比二者,饿汉式响应较快,懒汉式资源利用率上更高些,从线程安全的角度来说,饿汉式单例在线程访问单例类之前单例实例就已经创建完成了,不存在线程不安全这样的说法,懒汉式单例在线程访问单例类时,可能会多个线程进入判断单例为空的代码块,这样可能会创建多个线程,造成线程不安全的情况。

3、同步方法锁

package SingletonDemo;

//线程安全的懒汉式
public class Singleton3 {
    private Singleton3() {
    }

    private static Singleton3 singleton3;

    //同步方法锁,synchronized关键字修饰,临界资源的同步互斥
    public static synchronized Singleton3 getInstance() {
        if (singleton3 == null) {
            singleton3 = new Singleton3();
        }
        return singleton3;
    }
}

同步锁的颗粒度较大,效率不高,降低性能

4、同步代码块儿

package SingletonDemo;

//线程安全的懒汉式
public class Singleton4 {
    private Singleton4() {
    }

    private static Singleton4 singleton4;

    public static Singleton4 getInstance() {
        //使用synchronized关键字修饰,临界资源同步互斥
        synchronized ("") {
            if (singleton4 == null) {
                singleton4 = new Singleton4();
            }
            return singleton4;
        }
    }
}

同步锁的颗粒度有所减小,效率依然不高,性能依然不足

5、内部类

package SingletonDemo;

//线程安全的懒汉式
public class Singleton5 {
    private Singleton5() {
    }

    //内部类
    private static class Holder {
        private static Singleton5 singleton5 = new Singleton5();
    }

    //调用getInstance才会去调用内部类,加载Singleton5实例
    public static Singleton5 getInstance() {
        return Holder.singleton5;
    }
}

这种方式也是线程安全的,延时加载的懒汉式单例

6、双重检查(Double-Check)

package SingletonDemo;

//双重检查的懒汉式
public class Singleton6 {
    private Singleton6() {
    }

    //volatile关键字防止重排序
    private static volatile Singleton6 singleton6;

    public static Singleton6 getInstance() {
        //第一次检查
        if (singleton6 == null) {
            //确定为空之后在进入同步代码块,效率更高
            synchronized ("") {
                //只有第一次创建实例时才同步
                if (singleton6 == null) {
                    singleton6 = new Singleton6();
                }
            }
        }
        return singleton6;
    }
}

使用volatile关键字是为了保证操作可见性,新建单例实例时在JVM里面实际上分为多步,非原子操作,如果不加volatile关键字,可能会导致指令重排序

注:单例模式常被用于共享资源,如数据库连接池,线程池等场景

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值