java — 多线程设计模式


前言:

        本文章为作者原创,转载请注明出处,如该文章有技术问题,请指教,不胜感激。。


0528
一:多线程设计模式:
1、几种线程设计模式:
  • 单例模式
  • 不变模式
  • Future模式
  • 生产者消费者模式
2、什么是设计模式:
设计模式是指对软件设计的过程中普遍存在且反复发生的一些问题所提供出来的解决方案。

二:单例模式:
1、单例模式的种类
  • 懒汉式单例模式
  • 饿汉式单例模式
  • 登记式单例模式
2、单例模式的特点
  1. 单例模式只允许实例化一个实例;
  2. 单例模式只能自己实例化唯一的实例;
  3. 单例模式实例化唯一的实例之后需提供给外界调用;
3、懒汉式单利模式:
public class Singleton {
private Singleton() {};
private static Singleton singleton = null;
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}

如上代码实例所示,满足单例模式的三个条件,外接获取Singleton实例时必须通过 getInstance()方法进行获取,但是,以上为单例模式的一个简单实例,而且该实例是在不考虑java反射机制的情况下实现的,所以说是线程不安全的,但是如果将java反射机制运用到,该Singleton则会出现多个实例,所以,在考虑到线程安全的情况下使用单例模式则需要对 getInstance()方法进行改造:
改造1:在 getInstance()方法上面加上同步:
public class Singleton {
private Singleton() {};
private static Singleton singleton = null;
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
该改造在于每次去请求 getInstance()方法的时候都会被锁定,但是问题在于在多线程的情况下,如果Singleton这个单例类被频繁的引用的时候会造成系统阻塞,当前实例下只做了一个非空判断,如果进行深度的操作则会大幅度的影响系统性能。

改造2:双重检查锁定:
public class Singleton {
private Singleton() {};
private static Singleton singleton = null;
public static Singleton getInstance() {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
return singleton;
}
}

改造3:添加内部类:
public class Singleton{
public Singleton() {};
private class LazySingleton {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return LazySingleton.INSTANCE;
}
}
该改造在于就算使用java反射进行实例化多个Singleton时,实例化的只是Singleton,而其内部类LazySingleton不会被实例化,在获取这个单例的实例的时候通过getInstance()方法调用内部类,有效的保证了一个实例的情况,也同时去除掉了synchronized关键字,在大量线程进行频繁的访问的时候不会造成系统阻塞影响大量性能。
0606
三:不变模式:
1、概念:一个对象的状态在对象被创建之后就不在变化——出自《JAVA与模式》
2、应用场景:在并行开发的过程中,为了确保数据的一致性和正确性,有必要对对象进行同步操作,但是同步操作对系统性能有相当大的损耗,因此可以使用不变模式,依靠其不变性来确保并行操作在没有同步的情况下依旧保持它的不变性。
3、不变模式的三个必要条件:
  1. 对象的创建时必须给定初始数据;
  2. 当对象创建后,其内部状态和数据不能再发生任何改变;
  3. 对象必须能够被共享以及被多线程频繁访问;
4、一个不变模式的类的示例:
//类使用final进行修饰,防止产生子类
public final class ClassA {
//所有参数使用final进行修饰,防止后期进行修改,Object在此表示为可以为任意变量类型
private final Object paramA;
private final Object paramB;
private final Object paramC;

//无默认构造函数,该类必须在生成实例的时候进行赋值
public ClassA(Object paramA, Object paramB, Object paramC) {
this.paramA = paramA;
this.paramB = paramB;
this.paramC = paramC;
}

//参数没有set方法,只有get方法
public Object getParamA() {return this.paramA;};
public Object getParamB() {return this.paramB;};
public Object getParamC() {return this.paramC;};
}
5、不变模式的两种形态:弱不变模式和强不变模式:
弱不变模式:
   一个类的实例的状态是不可改变的;但是这个类的子类的实例具有可能会变化的状态。这样的类符合弱不变模式的定义。要实现弱不变模式,一个类必须满足下面条件:
  第一、所考虑的对象没有任何方法会修改对象的状态;这样一来,当对象的构造函数将对象的状态初始化之后,对象的状态便不再改变。
  第二、所有属性都应当是私有的。不要声明任何的公开的属性,以防客户端对象直接修改任何的内部状态。
  第三、这个对象所引用到的其他对象如何是可变对象的话,必须设法限制外界对这些可变对象的访问,以防止外界修改这些对象。如何可能,应当尽量在不变对象内部初始化这些被引用的对象,而不要在客户端初始化,然后再传入到不变对象内部来。如果某个可变对象必须在客户端初始化,然后再传入到不变对象里的话,就应当考虑在不变对象初始化的时候,将这个可变对象复制一份,而不要使用原来的拷贝。
  弱不变模式的缺点是:
  第一、一个弱不变对象的子对象可以是可变对象;换言之,一个弱不变对象的子对象可能是可变的。
  第二、这个可变的子对象可能可以修改父对象的状态,从而可能会允许外界修改父对象的状态。
 
  强不变模式:
   一个类的实例不会改变,同时它的子类的实例也具有不可变化的状态。这样的类符合强不变模式。要实现强不变模式,一个类必须首先满足弱不变模式所要求的所有条件,并且还有满足下面条件之一:
  第一、所考虑的类所有的方法都应当是final,这样这个类的子类不能够置换掉此类的方法。
  第二、这个类本身就是final的,那么这个类就不可能会有子类,从而也就不可能有被子类修改的问题。
 
  “不变"和"只读"的区别:
“不变”:任何情况下不会被改变;
“只读”:在特定的情况下会被改变;
6、常见实例:
  1. java.lang.String;
  2. java.lang.Boolean;
  3. java.lang.Byte;
  4. java.lang.Character;
  5. java.lang.Double;
  6. java.lang.Float;
  7. java.lang.Integer;
  8. java.lang.Long;
  9. java.lang.Short;
以上为不完全统计, 不变模式的改变不是改变了对象,而是改变了引用;
★:java.lang.Integer的加加操作:

在写代码的过程中,Integer的++操作是非常常见的,但是此处说到了java.lang.Integer是属于不变模式,那么两者是否存在冲突呢?其实不然,我们在使用Integer进行++操作的时候,其实是在内存中从新创建了一个Integer的对象,然后用新创建的Integer对象替换之前的对象,类似于一个=的操作,其装箱等操作在内部进行实现。

20180619
四:Future模式:
1、简单概念:
Futrue:翻译为未来,顾名思义,是指在访问一个接口或者服务的时候,先返回一个在可控范围内正常的返回值返回出去,再进行业务逻辑的操作,客户端在获取到服务端返回的Futrue返回值之后呢可以进行其他的一些业务操作,等到服务端处理完业务逻辑之后再降真正的返回结果返回给客户端,他的 核心思想为:异步调用



2、Future模式的简单实例:
/**
* <p>Title:Data.java</p>
* <p>Description: 数据操作通用接口</p>
*
* @author Robin
* @Date 2018-06-19
*/
public interface Data {
public String getContext();
}

/**
* <p>Title:RealData.java</p>
* <p>Description: 真实数据类</p>
*
* @author Robin
* @Date 2018-06-19
*/
public class RealData {
private String context;
//此处为模拟获取真实数据的复杂业务操作
public RealData(String context) {
try {
Thread.sleep(100000);
} catch (Exception e) {
}
this.context = context;
}
public void setContext(String context) {
this.context = context;
}
public String getContext() {
return this.context;
}
}

/**
* <p>Title:FutureData.java</p>
* <p>Description: 虚拟数据类</p>
*
* @author Robin
* @Date 2018-06-19
*/
public class FutureData implements Data {
private RealData realData = null;
p rivate boolean hasReal = false;

public synchrionzed void setRealData(RealData realData) {
if (realData == null) {
return;
}
this.realData = realData;
hasReal = true;
//通知所有使用此FutureData对象的线程终止阻塞;
notifyAll();
}

/**
* 调用getRealData方法之前会对hasReal进行校验,如果没有则会一直进行等待
*/
public synchrionzed RealData getRealData() {
while(!this.hasReal) {
try {
wait();
} catch (Exception e) {
}
}
return this.realData;
}
}

/**
* <p>Title:Client.java</p>
* <p>Description: 服务端模拟类</p>
*
* @author Robin
* @Date 2018-06-19
*/
public class Client {
public Data getRequest() {
private final FutureData futureData = new FutureData();
new Thread() {
public void run() {
RealData realData = new RealData(”Future text”);
future.setRealData(realData);
}
}.start();
return futureData;
}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值