多线程设计模式 Immutable模式

多线程设计模式之Immutable模式

Immutable就是不可变,不会发生改变的意思,这意味着一个类创建对象之后,该对象就无法被修改了。任何对该对象所做的修改,都将创建一个新的不可变对象。就例如Java.lang.String,一旦创建一个String对象,那么我们就不可以对它状态进行修改了,如果对它进行修改,那么就会创建新的String对象。

class StringTest{

    public static void main(String[] args) {
        String s1="123"; //创建一个字符串对象 值为123 
        String s2=s1; //我们将s1,s2对象引用同时指向"123"
        s1+="345"; //我们对s1进行修改
        System.out.println(s1.equals(s2));//结果为false 说明s1和s2引用的不是同一个对象了
    }

}

Immutable模式确保类的实例状态不会发生改变,那么该实例无论被多少个线程访问都不会发生改变,不需要执行线程的互斥处理,虽然 Immutable模式的缺点很多,但是我们巧妙利用,还是能在多线程中发挥很好的作用。

public final class ImmutableTest {

    private final Date date;//date虽然使用final指定,但是date是可变类 我们可以通过setTime()改变date的状态
  
    private final String str; //String本身就是不可变类 所以不需要对其进行考虑

    public ImmutableTest(Date date,String str) {
       
        long time=date.getTime();

        if(time<System.currentTimeMillis()){
            throw new IllegalArgumentException("Can not set it"+
            "for past time: "+date);
        }
        this.date=new Date(time); //新建一个Date类保证内部的date对象不会泄露出去改变其状态
        this.str=str;
    }

    public Date getDate() {    
        return (Date) date.clone(); //为了保持不变性 我们这里可以返回data的副本 那么外界的修改对data没有影响
    }

    public String getStr() {
        return str;
    }

    public static void main(String[] args) throws InterruptedException {
        Date date=new Date();
        ImmutableTest test=new ImmutableTest(date,"test");
        date=test.getDate();
        Thread.sleep(1000);
        date.setTime(System.currentTimeMillis());
        System.out.println(test.getDate().getTime());
        System.out.println(date.getTime());
    }
}

如何编写Immutable类呢? 需要注意一下几点。

  • 构造对象后不可修改对象内部的状态,即使可以修改,任何修改的结果都是产生新的不可变对象,例如String,修改后是新的对象,对原来对象的状态不影响。
  • 必须保证类内部的字段是私有的,且用final关键字修饰的。
  • 在对象构造的过程,必须保证不泄露任何对象。
  • 类应该用final修饰,避免子类继承父类会改变父类的不变性(强不变性),或者所有的方法都加上final(弱不变性).
  • getter()方法必须提供的是不可变的对象或者对象的副本。

Immutable类的优点

  • 不可变对象默认是线程安全的,可以在并发环境下不需要进行同步即可共享。
  • 简化了开发的难度,可以在多个线程中共享而不需要做额外的同步处理。
  • 减少了同步的处理,大大提高了开发效率。
  • 不可变对象的一大好处就是可重用性,我们可以缓存不可变对象并且重用他们。
    • 例如: 不变性保证了hashCode 的唯一性,因此可以放心地进行缓存而不必每次重新计算新的哈希码。而哈希码被频繁地使用, 比如在hashMap 等容器中。将hashCode 缓存可以提高以不变类实例为key的容器的性能。

Immutable类的缺点

  • 由于类的对象一创建就不可变了,若我们想修改它的状态,那么就必须新建一个不可变类,花费的代价是巨大的,不可避免地会产生大量的垃圾。
    • 字符串是一个主要的例子,它可以创建大量的垃圾,并且可能因为大量的垃圾回收而可能减慢应用程序。

猜你喜欢

转载自www.cnblogs.com/viscu/p/9783985.html