java 多线程访问单例_Java多线程编程之单例模式

延迟加载:“懒汉模式”

延迟加载是指在调用getInstance()方法时创建实例。常见的方法是在getInstance()方法中实例化new。实现代码如下:

2cf4d852d3708a5168bc21d2aa2afc48.png

但是因为getInstance()中有多个语句,所以可能存在线程安全问题。运行结果还表明:

2041531420

1348345633

1348345633

即使getInstance()中有更多的语句,也会有三个不同的对象。线程。.(3000)被添加到if(myObject==null)语句块。结果表明:

218620763

58615885

712355351

解决方案:DCL

如果使用synchronized关键字锁定整个getInstance()或整个if语句块,则会存在效率问题。

最后,采用DCL(double-Check Locking)双校验锁定机制,这也是大多数多线程结合单例模式的解决方案。第一层主要是为了避免不必要的同步,第二层是在空情况下创建实例。

440bd7d4ad37d10cd227b2b03953cf52.png

测试结果,得到的是相同的hashcode。

立即加载:“饿汉模式”

立即加载意味着在使用类时创建了对象。常见的实现方法是直接新实例化。也就是说,在调用方法之前,创建实例。示例代码如下:

1 class MyObject {

2 private static MyObject myObject=new MyObject();

3 private MyObject(){}

4 public static MyObject getInstance(){

5 //如果还有其他代码,存在线程安全问题

6 return myObject;

7 } 8 } 9 class MyThread extends Thread{ 10 @Override 11 public void run() { 12 System.out.println(MyObject.getInstance().hashCode()); 13 } 14 } 15 public class Run { 16 public static void main(String[] args) { 17 MyThread t1=new MyThread(); 18 MyThread t2=new MyThread(); 19 MyThread t3=new MyThread(); 20 t1.start(); 21 t2.start(); 22 t3.start(); 23 } 24 }

运行结果如下:

539e6c55972417370a021ddf83cdaa70.png

可以发现,实现了单例模式,因为多个线程得到的实例的hashCode是一样的。

静态内置类

55fb295e1601e3cbab56f0f9df5f4748.png

采用静态内置类的方法,是线程安全的。

使用static代码块

静态代码块的代码在重用类时执行,因此可以应用静态代码块的这个特性来实现单例设计模式。

324bbe32259745d2b3d1616ab605e660.png

使用enum枚举数据类型

当使用枚举类时,类似于静态代码块,自动调用构造函数。枚举由javac编译,并转换为诸如公共最终类T extends Enum之类的定义。也就是说,我们定义的枚举在第一次真正使用时由虚拟机加载和初始化,并且初始化过程是线程安全的。众所周知,解决单例并发问题的主要方法是初始化过程中的线程安全问题。

因此,由于枚举的上述特性,枚举实现了固有的线程安全的单例。同时,枚举可以解决反序列化会破坏单例的问题。

enum MyObject{

INSTANCE;

}

SimpleDataFormat

SimpleDataFormat使用带有线程安全问题的单例模式。SimpleDateFormat中的日期格式不同步。建议(建议)为每个线程创建单独的格式实例。如果多个线程同时访问一种格式,则它必须保持外部同步。

解决方案1:需要的时候创建新实例

455d6062d56dcc818a542ff62647a031.png

在需要SimpleDateFormat的地方创建新实例可以通过在任何时候将线程安全的对象从共享更改为本地私有来避免多线程,但是它也增加了创建对象的负担。一般来说,对性能的影响不是很明显。

解决方案2:同步SimpleDateFormat对象

a8461928665be20243ec9867e75c2f7c.png

当有更多的线程时,当一个线程调用此方法时,其他想要调用此方法的线程需要块。当多线程并发性较大时,会对性能产生一定的影响。

解决方案3:使用ThreadLocal

fba2b8ba294283f7ad7880dc6e832380.png

ThreadLocal还用于将共享变量转换为独占变量。ThreadLocal肯定比方法独占性减少了在并发环境中创建对象的开销。如果性能要求很高,通常建议使用这种方法。

https://www.cnblogs.com/aishangJava/category/967272.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值