Java语言多线程编程之不可变对象模式实例讲解
小标 2018-12-04 来源 : 阅读 1277 评论 0

摘要:本文主要向大家介绍了Java语言多线程编程之不可变对象模式实例讲解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

本文主要向大家介绍了Java语言多线程编程之不可变对象模式实例讲解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。


在多线程环境中,为了保证共享数据的一致性,往往需要对共享数据的使用进行加锁,但是加锁操作本身就会带来一定的开销,这里可以使用将共享数据使用不可变对象进行封装,从而避免加锁操作。


1. 模型角色


不可变对象指的是,对象内部没有提供任何可供修改对象数据的方法,如果需要修改共享变量的任何数据,都需要先构建整个共享对象,然后对共享对象进行整体的替换,通过这种方式来达到对共享对象数据一致性的保证。如下是不可变对象设计的类图


不可变对象类图


如下是各个角色功能的描述:


ImmutableObject:不可变对象的载体。对于需要一致性更改的数据,都需要放入不可变对象中,对于不可变对象,需要注意如下几点:


不可变对象的属性必须使用final修饰,以防止属性被意外修改,并且final还可以保证JVM在该对象构造完成时该属性已经初始化成功(JVM在构造完对象时可能只是为其分配了引用空间,而各个属性值可能还未初始化完成);


属性的设值必须在构造方法中统一构造完成,其余的方法只是提供的查询各个属性相关的方法;


对于可变状态的引用类型属性,如集合,在获取该类型的属性时,必须返回该属性的一个深度复制结果,以防止不可变对象的该属性值被客户端修改;


不可变对象的类必须使用final修饰,以防止子类对其本身或其方法进行修改;


Manipulator:聚合对象的管理类(某些情况可不用)。对于聚合对象的管理,主要有两部分:查询和修改。对于聚合对象的查询,只需要根据一定的规则在Manipulator类中获取该对象即可,对于聚合对象的修改,需要首先通过参数构造一个完整的聚合对象,然后将保存的该聚合对象的引用进行替换即可;


Client:获取聚合对象的客户端应用。


2. 使用场景


对于不可变对象,其主要有如下三种使用场景:


当某组数据变化不是很频繁,则可以使用不可变对象。对于数据的访问,由于不可变对象的引用空间不会发生变化,因而任何线程都可以保有同一个不可变对象的引用,这样可以减少内存的消耗,也能保证数据访问的一致性;


当某组数据需要进行一致性的更新操作时,可以使用不可变对象。由于不可变对象能够保证对其任何数据的修改都是对整个对象的替换,因而其能够保证整组数据的一致性。需要注意的是,如果该组数据变更比较频繁,则不宜使用不可变对象,因为这会造成创建大量的不可变对象,从而增加JVM垃圾回收的压力。具体的情况应根据JVM可使用内存大小与对象更新的频率进行考量;


当需要对象作为Map的键时可以使用不可变对象。对于Map而言,其hashCode()方法默认返回的是对象的引用地址,而对于不可变对象而言,由于其引用地址是不会发生变化的,因而即使不对其hashCode()方法进行重写,其也不会发生变化。


3. 使用示例


对于不可变对象,一个很好的例子就是地址经纬度。笔者所工作的公司处理的业务和房源相关,其中有一部分就是需要处理房源所在点的经纬度信息,这里就可以使用不可变对象,因为房源经纬度基本上不会发生变化,并且对其操作也主要是以查询为主,最重要的是,对经纬度的处理必须是经度和纬度同时发生变化,任何情况下只更改了其中一个数据都会产生问题。如下是记录房源经纬度的类:


public final class Location {

  private final long id;

  private final String latitude;

  private final String longitude;

 

  public Location(long id, String latitude, String longitude) {

    this.id = id;

    this.latitude = latitude;

    this.longitude = longitude;

  }

 

  public long getId() {

    return id;

  }

 

  public String getLatitude() {

    return latitude;

  }

 

  public String getLongitude() {

    return longitude;

  }

}

   


该Location类也即上述UML类图中的ImmutableObject部分。可以看到,任何对Location对象的修改都必须重新构建一个Location对象。如下是对Location的管理类,用于存储具体的Location信息的:


public class LocationHolder {

   

  private final LocationHolder INSTANCE = new LocationHolder();

  private Map<long, location=""> locations;

 

  private LocationHolder() {

    this.locations = new ConcurrentHashMap<>();

  }

   

  public LocationHolder getInstance() {

    return INSTANCE;

  }

 

  public Location getLocation(long id) {

    return locations.get(id);

  }

 

  public void addLocation(long id, String latitude, String longitude) {

    Location location = new Location(id, latitude, longitude);

    locations.put(id, location);

  }

   

  public Map<long, location=""> getLocations() {

    return Collections.unmodifiableMap(locations);

  }

}</long,></long,>

   


可以看到,这里对Location的管理是通过一个单例类LocationHolder进行的,任何对Location的操作都进行了封装,并且这里批量获取Location,也是返回了一个不可变Map,从而保证原始数据不会作任何修改,如果该Map的键或值任何一方可能发生变化,那么在返回值则必须返回一个深度复制的结果,这样才能保证原始数据的完整性。


          

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注编程语言JAVA频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved