设计模式-单例模式
什么是单例模式
单例模式是为了避免实例(对象)重复创建造成对资源的浪费,我们使用单例模式主要目的就是为了保证只创建一个对象。
码完一段文本的我,拿着我桌角的水杯一饮而尽,又要起身去五十米开外的饮水机处接水,唉…要是每人配一台饮水机就好了,很显然这是不现实的每人一个饮水机需要资金 空间 电费 重要是这些饮水机对于每个人来说并不是实时需要的,这就会造成资源的浪费。
不使用单例模式
可以看到下图张三和李四想要喝水但是分别创建一个饮水机对象(通过地址值不同来区分是否是同一个对象 红色部分为地址值)。这样确实可以使用对象里面的功能但是却对系统资源造成了浪费,因为使用一个对象就可以完成此操作,单例模式目的就是全局创建一个对象避免资源浪费。
代码的实现
不同的实现方式对资源的消耗,线程的安全是不一样。
饮水机类:
package com.houyongchun.designpattern.singleton;
/**
* @author tjc
* @version 1.0
* @date 2021/3/29 0029 12:45
* @description 饮水机类
*/
public class DrinkingFountain {
public String getWater(){
return "饥渴的少年获取到了杯水!!!";
}
}
方式一饿汉式
使用static静态修饰保证此对象只创建一次,因为是类加载的时候直接创建饮水机对象所以也称为饿汉式
package com.houyongchun.designpattern.singleton;
/**
* @author tjc
* @version 1.0
* @date 2021/3/29 0029 12:45
* @description 这是单例模式饿汉式实现方式
*/
public class WaterDispenserFactoryHungry {
private static DrinkingFountain drinkingFountain = new DrinkingFountain();
public static DrinkingFountain getDrinkingFountain() {
return drinkingFountain;
}
}
张三使用单例模式打水
张三使用单例模式打水
由此可见当是用单例模式时获取到的是同一个对象,避免对象重复创建造成资源浪费(由地址值确认是否是同一个对象)
方式二懒汉式(线程不安全版)
懒汉模式主要代码:
李四使用懒汉模式代码:
张三使用懒汉模式代码:
为什么称为懒汉式:此种单例模式并不像饿汉式一样类加载直接创建对象,而是需要时判断当前对象是否存在如果存在直接返回 ,不存在创建并返回,所以称为懒汉。
为什么线程不安全: 很多单例模式的描述都会说懒汉模式是线程不安全的,那么为什么线程不安全那?线程不安全又会导致什么后果?
可以看到我在懒汉模式实现代码加入了A,B两个位置标记,当线程1李四进入到A位置判断当前对象是否创建如果是第一次没创建,线程1进入到B位置,还没进入到创建对象的操作 线程2张三突然执行了进入到A位置判断对象是否存在因为线程1李四还没有创建对象所以 线程2张三判断对象为空也进入到B位置 创建了对象并返回结束了操作,线程1李四开始执行创建对象的操作并返回。这样就导致了对象的重复创建。
如何解决线程不安全问题:如果线程1李四进入到判断创建对象操作时其他线程禁止进入此处那我们就可以避免对象重复创建问题
同步锁:我们使用synchronized关键字创建了一个同步代码块,当线程1李四进入到了同步代码块,其他线程就会无法进入此处,只有当线程1执行完其他线程才会有进入的权力,这样也就避免了对象的重复创建!
package com.houyongchun.designpattern.singleton;
/**
* @author tjc
* @version 1.0
* @date 2021/3/30 0030 12:44
* @description 单例模式-懒汉式-线程不安全
*/
public class SingletonLazyMan {
private static DrinkingFountain drinkingFountain = null;
public static DrinkingFountain getDrinkingFountain() {
synchronized (new Object()){
if (drinkingFountain==null){
drinkingFountain = new DrinkingFountain();
}
}
return drinkingFountain;
}
}
小结:使用懒汉模式也可以完成实例只创建一次的目的,并且不使用不创建这样不会造成资源的浪费,使用同步synchronized关键字可以使线程安全。饿汉模式直接创建对象因为是静态的只会创建一次所以不存在线程安全问题但是他并不是懒加载的这样可能会造成资源的浪费,因为我不管需不需要当类被加载都会创建对象。
以上实现的懒汉其实有性能问题,我们可以使用双锁解决,也可以使用登记式单例模式 既解决了线程安全又是懒加载。
单例模式其他写法不做展示,大家可以到其他地方学习,本文已将主要思想和为什么线程不安全问题解决了,其他的也只是优化所以博主不做实现了因为太简单了…(主要是我懒…)