Java 经典设计模式-- 05.并发型模式

前言

书接上文,终于来到了设计模式篇最硬核的并发设计模式介绍篇了,上一篇中对 Java 8 的行为模式中的常用设计模式做了介绍与分析,本篇将对 Java 8 的并发模式中的常用模式做介绍与分析,为了为整个 Java 8 设计模式篇章践行,本篇将对 Wiki 上几乎所有的并发模式做介绍与分析,由于并发模式并不属于典型的设计模式,所以它们的跨度和分散知识可能就很多。目录:

  • 双重检查锁定
  • 阻碍模式
  • 守卫模式
  • 线程特定存储
  • 反应器模式
  • 基于事件的异步模式

简单提及

  • 线程池模式
  • 调度模式
  • Lock 模式
  • 消息设计模式
  • 读写锁模式

双重检查锁定模式

双重检查锁定模式(也被称为"双重检查加锁优化",“锁暗示”(Lock hint)[1]) 是一种软件设计模式用来减少并发系统中竞争和同步的开销。双重检查锁定模式首先验证锁定条件(第一次检查),只有通过锁定条件验证才真正的进行加锁逻辑并再次验证条件(第二次检查)。
该模式在某些语言在某些硬件平台的实现可能是不安全的。有的时候,这一模式被看做是反模式。摘自 Wiki

双重检查锁定模式已经被定义为了“反模式”,并且不推荐使用,这里可以通过了解一下双重检查锁定模式来一窥 JVM 对象初始化的过程与 volatile 关键字的作用。Wiki 通过实现一个单例模式来体现双重检查锁定模式,这里引用一点创建行模式 – 单例模式中的代码,正如之前在创建型模式 – 单例模式中说的,在单线程环境中不做线程安全检查的代码不会有问题

/**乞丐版懒汉单例模式**/
public class InitialSingleton {
   

    private static InitialSingleton singleton = null; //懒汉

    private InitialSingleton() {
   
		/**外部逻辑**/
    }

    public static InitialSingleton getInstance() {
   
        if (singleton == null) {
   
            return new InitialSingleton();
        }
        return singleton;
    }
}
--------------------- 
作者:六尕娃 
来源:CSDN 
原文:https://blog.csdn.net/wufeiova/article/details/91790594 
版权声明:本文为博主原创文章,转载请附上博文链接!

但是在多线程中就会因为可见性与一致性问题导致程序运行不符合预期。所以就有了标准饿汉式单例模式

/**标准懒汉单例模式**/
private BasicLazySingleton(){
   }

private BasicLazySingleton instance = null; //饿汉

public static synchronized BasicLazySingleton getInstance() {
    //线程安全方法,保证了不会出现多线程同时新建单例对象的情况
    if (instance == null) {
   
        instance = new BasicLazySingleton();
    }
    return instance;
}
--------------------- 
作者:六尕娃 
来源:CSDN 
原文:https://blog.csdn.net/wufeiova/article/details/91790594 
版权声明:本文为博主原创文章,转载请附上博文链接!

但是这种方式在第一次加载之后,以后每次获取的时候还需要获取锁,释放锁,其实是没有必要的,性能白白浪费,所以有些人就想到了使用以下方式进行优化

private BasicLazySingleton(){
   }

private BasicLazySingleton instance = null; //饿汉

public static synchronized BasicLazySingleton getInstance() {
    //线程安全方法,保证了不会出现多线程同时新建单例对象的情况
    if (instance == null) {
    //检查是否已经初始化过了
    	synchronized(this) {
    //没有初始化,获取锁
    		if (instance == null) {
    //再次检查变量是否已经被初始化过
    			instance = new BasicLazySingleton(); //如果依然没有,进行初始化
    		}
    	}
    }
    return instance; //返回
}

直觉上,这个算法看起来像是该问题的有效解决方案。然而,这一技术还有许多需要避免的细微问题。例如,考虑下面的事件序列:
线程A发现变量没有被初始化, 然后它获取锁并开始变量的初始化。
由于某些编程语言的语义,编译器生成的代码允许在线程A执行完变量的初始化之前,更新变量并将其指向部分初始化的对象。
线程B发现共享变量已经被初始化,并返回变量。由于线程B确信变量已被初始化,它没有获取锁。如果在A完成初始化之前共享变量对B可见(这是由于A没有完成初始化或者因为一些初始化的值还没有覆盖B使用的内存(缓存一致性)),程序很可能会崩溃。 摘自Wiki

这个问题就在于线程 A 初始化变量到一半,就已经不为 null 了,但是这个时候它其实没有完全初始化完毕,这个时候 B 线程判断变量已经初始化完成了,直接返回,导致程序异常。
使用 volatile 或者 final 关键字可以解决这个问题,volatile 会在编译成机器指令的时候对前后的操作加上内存屏障,解决了可见性的问题,以下是使用 volatile 的方式

/**高富帅懒汉单例模式**/
public class BasicLazySingleton {
   

    private static boolean initialized = false; //单例初始化标志位,添加 volatile 保证其可见性
	
	private DBProperties dbProperties;

    private BasicLazySingleton() {
   
    	synchronized (BasicLazySingleton.class) {
    //保证线程安全
	        if (!initialized) {
    //首次初始化
	            initialized = true; //改变标志位
				
				/**业务逻辑部分**/
				dbProperties = null;
	        } else {
    //多线程同时初始化时,由于 volatile 内存屏障对可见性的保证,initialized 一定已经是 true 了
	            throw new RuntimeException("单例已经被初始化过"); //抛出异常
	        }
        }
    }

	//final 保证了方法不被重写
    public static final BasicLazySingleton getInstance() {
   
        return BasicLazySingletonHolder.LAZY;
    }

	public DBProperties getDbProperties {
   
		return dbProperties;
	}

	/**
	根据 Java 特性
	1、使用内部类,规避了 JVM 加载外部类的时候就单例进行初始化
	2、在外部类被调用的时候内部类才会被加载(类的懒加载)
	3、内部类必须在方法调用之前初始化(对象的懒加载,所以调用 BasicLazySingletonHolder.LAZY 之前,才会去构造 BasicLazySingleton)
	4、由 static 对外部的可见性
	5、final 保证了 LAZY 不被重写
	**/
    static class BasicLazySingletonHolder {
   
        private static final BasicLazySingleton LAZY = new BasicLazySingleton();
    }
}

以上就是对于反面教材双重检查锁定模式与如何避免的介绍与分析。

阻碍模式

The balking pattern is a software design pattern that only executes an action on an object when the object is in a particular state. For example, if an object reads ZIP files and a calling method invokes a get method on the object when the ZIP file is not open, the object would “balk” at the request. In the Java programming language, for example, an IllegalStateException might be thrown under these circumstances.
There are some specialists in this field who consid

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java设计模式是一组经过实践验证的面向对象设计原则和模式,可以帮助开发人员解决常见的软件设计问题。下面是常见的23种设计模式: 1. 创建型模式(Creational Patterns): - 工厂方法模式(Factory Method Pattern) - 抽象工厂模式(Abstract Factory Pattern) - 单例模式(Singleton Pattern) - 原型模式(Prototype Pattern) - 建造者模式(Builder Pattern) 2. 结构型模式(Structural Patterns): - 适配器模式(Adapter Pattern) - 桥接模式(Bridge Pattern) - 组合模式(Composite Pattern) - 装饰器模式(Decorator Pattern) - 外观模式(Facade Pattern) - 享元模式(Flyweight Pattern) - 代理模式(Proxy Pattern) 3. 行为型模式(Behavioral Patterns): - 责任链模式(Chain of Responsibility Pattern) - 命令模式(Command Pattern) - 解释器模式(Interpreter Pattern) - 迭代器模式(Iterator Pattern) - 中介者模式(Mediator Pattern) - 备忘录模式(Memento Pattern) - 观察者模式(Observer Pattern) - 状态模式(State Pattern) - 策略模式(Strategy Pattern) - 模板方法模式(Template Method Pattern) - 访问者模式(Visitor Pattern) 4. 并发型模式(Concurrency Patterns): - 保护性暂停模式(Guarded Suspension Pattern) - 生产者-消费者模式(Producer-Consumer Pattern) - 读写锁模式(Read-Write Lock Pattern) - 信号量模式(Semaphore Pattern) - 线程池模式(Thread Pool Pattern) 这些设计模式可以根据问题的特点和需求来选择使用,它们提供了一些可复用的解决方案,有助于开发高质量、可维护且易于扩展的软件系统。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值