Java设计模式之单例模式

所谓单例模式,也就是只有一个类,只会创建一个实例;
又由于类实例化是通过其构造方法实现的,所以为了保证一个类只有一个实例,我们可以对其的构造方法进行改造,使其只可以创建一个实例:
对于普通的类,大多数情况下,我们没有在类中写构造方法时,在运行中,每个方法都会有一个默认的无参构造方法,所以一个普通类的大致结构如下

//一个普通方法的整体结构
public  class  Demo{
public  Demo(){
//我是普通类的无参构造方法
{
}

//要想其只创建一个单例,其构造方法就不能被其他方法调用,其访问权限也必须为private
public  class  Demo{
//1创建私有变量,demoInstance,用做该demo的唯一实例
//2内部消化,进行实例化
private static Demo demoInstance= new Demo();
//3将类的构造方法也私有化
private Demo(){
}
//4定义一个公共方法,提供一个全局的唯一访问点
//5外部通过调用getInstance方法,来获的唯一的实例,和类的封装很类似,
public static Demo newInstance(){//这里为什么是newInstance,这里涉及到了Java的反射机制,在程序运行时,创建其对应的对象,使用的是newInstance,而不是new 关键字
return demoInstance;
}
}

以上就是一个单例模式和普通类的大致类结构了
这里提前总结一下:
所谓单例模式,除了枚举类型,其他五种单例模式,其实就是在内部创建一个私有化实例&将构造方法私有化&设置一个唯一的全局访问点,用来获取内部创建的实例

其单例模式的优点:
提供了对唯一实例的受限访问
一个类只有一个实例,减少了内存的消耗,对于一些频繁创建和销毁的类来说,大大提供了系统的性能
同时我们可以在单例模式上扩展出双例或多例模式
缺点:
由于一个类只会创建一个实例,所以该单例的职责会很重大,其代码可能会过于复杂,在一定程度上,可能会违背单一职责原则
若实例化的对象,长时间不被调用,就会被垃圾回收机制,视为垃圾而回收,这将会 导致对象状态丢失

单例模式的实现方法:
其实实现方法也很简单,虽然有6种但是每种都会有很强的联系,只需要掌握其相关联系,就很容易掌握了
首先,
1饿汉式:
也称为最简单的单例模式的实现

原理,依赖JVM类加载机制,保证单例只会被创建一次,即线程安全
1JVM在类的初始化阶段(在类被加载后,线程调用前),会执行类的初始化
2在执行类的初始化期间,JVM会去获取一个锁,该锁可以同步多个线程对同一个类的初始化

class  Singleton{
//1加载该类的时候,就自动创建单例的实例
private  static  Singleton demoInstance=new Singlieton();
//2将构造函数的访问权限设置为私有
private Singleton(){
}
//3通过调用静态方法获取创建的单例
public  static  Singleton newInstance(){
return  demoInstance;
}
}

该模式特点:对象初始化速度快&占用内存小&安全

2枚举类型

public enum Singleton{
INSTANCE;//定义一个枚举的元素,即为单例类的一个实例
}
//获取单例的方式
Singleton singleton=Singleton.INSTANCE;

以上是最简洁的单例实现方式,且其和饿汉式都是属于提前直接创建单例,
接下来有另外一种按需创建单例

3懒汉式:
就很懒,非要到用的时候,才创建,不会提前创建
与饿汉差别,饿汉会提前创建,就这一个主要差别,其他一样
具体实现

class  Singleton{
//不提前创建,只有再需要时,创建
private static Singleton demoInstance=null;
private Singleton(){
}
//3需要时,才调用Instance进行创建
public static Singleton newInstance(){
//判断单例是否为空引用,从而避免重复创建
if(demoInstance==null)
{
demoInstance=new Singleton();
}
return demoInstance;
}
}

该懒汉模式优点,更加灵活,
缺点:是线程不安全的,
于是就出现了下面的另外一个模式

4同步锁:(懒汉式的一个改进)
使用同步锁synchronize锁住创建单例的方法,防止多个线程同时调用,从而避免创建出多个实例
1,一个getInstance只能运行在一个线程中
2若已经在一个线程中被调用,其他要想继续调用,只会阻塞而等待

class   Singleton{
//1类加载时,只创建一个引用
private static Singleton demoInstance=null;
 //2将构造函数的访问权限设置为私有
 private Singleton()
 {
 }
//现在需要该对象了,创建对象,加入同步锁
private  static synchronized Singleton getInstance(){//同步锁相比懒汉式,就多加了一个同步锁sycnhronized
if(demoInstance==null)
{
demoInstance=new Singleton();
}
return demoInstance;
}
}

优点,使其变成了线程安全的,
缺点:每次访问时,都会调用到同步锁synchronized,造成锁的浪费
于是我们就又有了下面这个模式
5双重校验锁,同样是对懒汉式的改进
原理:在同步锁的 基础之上,添加一个判断,判断该单例是否已经创建,若创建就不需要进行加锁,若未创建就需要加锁,这样就方便了很多

class   Singleton{
//1类加载时,只创建一个引用
private static Singleton demoInstance=null;
 //2将构造函数的访问权限设置为私有
 private Singleton()
 {
 }
//现在判断对象是否被创建,考虑加不加锁
private  static  Singleton getInstance(){
if(demoInstance==null)
//为空,加入锁
synchronized(Singleton.class){
if(demoInstance==null){
demoInstance=new Singleton();
}
return demoInstance;
}
}
}

优点:解决了浪费锁的问题
缺点:判断太多,过于复杂
于是又出现了静态内部类,简化操作
6静态内部类:
原理:
静态内部类中创建单例,在加载该内部类时才会去创建这点很好的 达到了我们的要求,需要时创建

class Singleton{
//创建一个静态内部类
private static class Singleton2{
//1创建一个访问权限为private的静态内部类对象
private  static Singleton demoInstance=new  Singleton();
}
//将构造方法私有化
private Singleton()
{
}
//加载到对应的内部类时就会创建
public static Singleton newInstance(){
return  demoInstance;
}
}

流程:
1当外部调用该Singleton的newInstance方法
2自动调用Singleton2.demoInstance
3此时该静态内部类会被初始化,得到该单例
4接下来通过newInstance方法,返回该单例
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值