多线程设计模式——Immutable Object(不可变对象)

设计模式是对软件成特定的场景下普遍存在的问题一般性可重复用的解决方案。简单来说就是对一类问题的普遍解决方案。
这些都是根据我最近看的《Java实战指南多线程编程(设计模式篇)》这里所得

模式名称

Immutable Object(不可变对象)

问题

多线程环境中,一个对象常常会被多个线程共享,这个时候会有一个对象被不同的线程做不同的修改的问题,所以我们需要做一些事情来保证对象的一致性。

解决方案

用一个ImmutableObject类来存储不可变值的信息,改参与者不对外暴露任何可以修改其状态的方法,另一个类负责维护上一个类所创建信息的实体的变更,党相应的现实实体状态变更是,改参与者负责生成新的ImmutableObject,以反应新的状态。

代码

这是书上的例子,是真实需求代码的例子。
需求是:某彩信网管系统在处理有增值业务提供商下发给手机终端用户的彩信消息是,需要根据彩信接收方号码的前缀选择对应的彩信中心,然后转发消息给选中的彩信中西,由其负责对接电信网络讲彩信消息下发给手机终端用户。
彩信中心路由器规则管理器代码(信息处理类)

public class MMSCRouter {
    //用volatile修饰,保证多线程环境下改变量的可见性
    private static volatile MMSCRouter instance = new MMSCRouter();
    //维护手机号码前缀到彩信中心之间的映射关系
    private final Map<String,MMSCInfo> routeMap;
    public MMSCRouter(){
        //讲数据库表中的数据加载到内存,存为Map
        this.routeMap = MMSCRouter.retrieveRouteMapFromDB();
    }

    private static Map<String,MMSCInfo> retrieveRouteMapFromDB(){
        Map<String,MMSCInfo> map = new HashMap<String,MMSCInfo>();
        //省去和设计模式无关的代码
        return map;
    }

    public static MMSCRouter getInstance(){
        return instance;
    }

    //根据手机号码前缀获取对应的彩信中心信息
    public MMSCInfo getMMSC(String missdnPrefix){
        return routeMap.get(missdnPrefix);
    }

    //讲当前MMSCRouter的实力更新为制定的新实例
    public static void setInstance(MMSCRouter newInstance){
        instance = newInstance;
    }

    private static Map<String,MMSCInfo> deepCopy(Map<String,MMSCInfo> m){
        Map<String,MMSCInfo> result = new HashMap<String,MMSCInfo>();
        for(String key : m.keySet()){
            result.put(key, new MMSCInfo(m.get(key)));
        }
        return result;
    }

    public Map<String,MMSCInfo> getRouteMap(){
    //防御性复制
        return Collections.unmodifiableMap(deepCopy(routeMap));
    }
}

彩信中心信息(存储信息类)

public class MMSCInfo {
    private final String deviceID;//设备编号
    private final String url;//彩信中心URL
    private final int maxAttachmentSizeInBytes;//该彩信锁允许的最大附件的大小

    public MMSCInfo (String deviceID,String url,int maxAttachmentSizeInBytes){
        this.deviceID = deviceID;
        this.url =url;
        this.maxAttachmentSizeInBytes = maxAttachmentSizeInBytes;
    }

    public MMSCInfo(MMSCInfo prototype){
        this.deviceID = prototype.deviceID;
        this.url = prototype.url;
        this.maxAttachmentSizeInBytes = prototype.maxAttachmentSizeInBytes;
    }

    public String getDeviceID() {
        return deviceID;
    }

    public String getUrl() {
        return url;
    }

    public int getMaxAttachmentSizeInBytes() {
        return maxAttachmentSizeInBytes;
    }
}

与运维中心对接的类(线程逻辑类)

public class OMCAgent extends Thread{
    @Override
    public void run(){
        boolean isTableModificationMsg = false;
        String updateTableName = null;
        while(true){
            //忽略与设计模式无关的代码
            //从与OMC链接的Socket中读取消息并进行解析,
            //解析到数据表更行消息后,重置MMCRouter实例
            if(isTableModificationMsg){
                if("MMSCInfo".equals(updateTableName)){
                    MMSCRouter.setInstance(new MMSCRouter());
                }
            }
            //忽略与设计模式无关的代码
        }
    }
}

适用场景

  1. 被建模对象的状态变化不频繁
  2. 同时对一组相关的数据进行写操作,因此需要保证原子性
  3. 适用某个对象作为安全的HashMap的Key

需要注意的问题

  1. 被建模对象的变更比较频繁的时候尽量不要使用
  2. 使用等效或者近似的不可变对象
  3. 防御性复制
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值