单例模式 java特点_简单了解Java中的单例模式

前言

看到这个题目,相信大家都知道了,Java中单例模式的写法有好几种,那么我们怎么去实现呢,还有我们为什么要使用单例模式呢,这是我们本文需要研究的问题。接下来闲话少说了,直接进入我们的正题“单例模式”。

1.什么是单例

一个类在整个系统中只有一个实例,而且这个实例是在类的内部通过一个private的构造方法构造的,外部不能调用其构造方法,只能获取它的实例。

2.目的

拿正常的系统来说,我们需要登录,登录之后呢,会看到一个在线登录人数的。这个登录人数是使用计数器做到的,如果同时好几个人同时登录系统的话,获取系统中的数据,然后都加1,然后存储到文件或者缓存或者数据库中。这样操作后续登陆的用户得到的在线人数,与实际的在线人数并不一致。所以这样,我们就需要把计数器设计成一个全局对象,所有的人都共用同一个数据,这样就避免了登录用户和在线人数不同的问题,这样就用到了我们所说的单例模式了。

单例模式能确保一个类只有一个唯一的实例,并向外部提供一个全局的访问点。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。

3.单例模式的特点单例类只能有一个实例

单例类必须自己创建自己的唯一实现

单例类必须给其他对象提供这一实例

现在讲一下两种简单的单例模式:

1.懒汉式单例

懒汉模式,我们可以理解为,在我们使用这个对象的时候,判断内存中是否已存在该对象,如果不存在就立马创建,如果存在则不在创建,直接返回。

懒汉模式只在外部对象第一次请求对象的时候才去创建。

2.饥汉式单例

饿汉模式,我们可以理解为,在这个类加载的时候,对象就已经创建好了。

下面做一个对这两种单例模式的使用和优缺点,以及更正做简单的介绍。

创建线程类,使用for循环创建多线程,模拟高并发

public class MyThread extends Thread {

@Override

public void run() {

Singleton singleton = Singleton.getInstance();

//获取singleton对象的hashcode值

System.out.println(singleton.hashCode());

}

}

创建单例

1.懒汉模式(普通模式,只适合单线程,线程不安全,不可用)

public class Singleton {

private static Singleton singleton= null;

// 懒汉式单例类.在第一次调用的时候实例化自己private Singleton() {

}

public static Singleton getInstance() {

if (singleton== null) {

singleton= new Singleton();

}

return singleton;

}

}

使用多线程测试,打印一下,我们实例的hashcode值,看看我们拿到的是不是同一个对象。

我们看到,hashcode是不一样的,所以上面这种事线程不安全的,不能使用。

下面的介绍,暂且不提供结果展示了,自己亲身测试一下,会比较理解。

2.懒汉模式(synchronized同步代码块,线程安全,不推荐使用)

public class Singleton {

private static Singleton singleton= null;

// 懒汉式单例类.在第一次调用的时候实例化自己

private Singleton() {

}

public static synchronized Singleton getInstance() {

if (singleton== null) {

singleton= new Singleton();

}

return singleton;

}

}

这种方式就是在第一种的情况下使用了同步锁(synchronized),每次通过getInstance方法得到singleton实例的时候都要去获取同步锁。大家都知道,加锁是比较耗时的,所以这种当时

3.懒汉模式(加synchronized同步锁时,前后两次判断实例是否存在(可行))

public class Singleton {

private static Singleton singleton=null;

private Singleton(){

}

public static Singleton getInstance(){

if(singleton==null){

synchronized(Singleton.class){

if(singleton==null){

singleton=new Singleton();

}

}

}

return singleton;

}

}

在程序运行过程中,只有当singleton为null时,才需要我们获取同步锁,并创建一次实例。当实例已经被创建,则无需试图加锁。但是我们在单例中使用了双重的if判断,逻辑变得比较复杂,容易出错。

4.饥汉式模式(线程安全,可以使用)

public class Singleton {

private static Singleton singleton=new Singleton();

private Singleton(){

}

public static Singleton getInstance(){

return singleton;

}

}

只有在初始化静态的singleton对象时被创建一次。如果我们在Singleton类里面写一个静态的方法不需要创建实例,它仍然会早早的创建一次实例。因为没有延迟加载的效果,所以降低内存的使用率。

5.静态内部类(线程安全,可以使用)

public class Singleton {

private Singleton(){

}

private static class SingletonHolder{

private final static Singleton singleton=new Singleton();

}

public static Singleton getInstance(){

return SingletonHolder.singleton;

}

}

定义一个私有的内部类,在第一次用这个嵌套类时,会创建一个实例。而类型为SingletonHolder的类,只有在Singleton.getInstance()中调用,由于是私有的属性,其他对象无法使用SingleHolder,不调用Singleton.getInstance()就不会创建实例,也不能在外部实例化对象。而且还达到了延迟加载的效果,在需要的时候再创建实例,很大程度的提高了内存的使用率。

说了这么多,做了这么多的实验,那么使用单例模式的好处又是什么呢?

1、控制资源的使用,通过线程同步来控制资源的并发访问;

2、控制实例产生的数量,达到节约资源的目的。

3、作为通信媒介使用,也就是数据共享,它可以在不建立直接关联的条件下,让多个不相关的两个线程或者进程之间实现通信。

单例模式就先讲这么多,我是个菜鸟,就能理解这么多了,各位大神,有什么错误还请指正一下,自己再做更正,实现更大的进步。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值