java并发(六、不可变对象)

如果一个对象在构造之后不可改变,那么这个对象就是不可变对象。不可变对象被广泛认同的作用是建立简单、可靠代码的万全之策。

    不可变对象在并发应用程序中特别有用,因为他们不能被修改,他们不能发生线程冲突,或者发生不一致状态的读取。

    程序员经常不心甘情愿的使用不可变对象,因为他们不能修改这个对象,只能new一个对象。创建对象的开销一般是被评估过高的,可以和不可能变对象相关的效率问题抵消。包括,垃圾回收的开销和the elimination of code needed to protect mutable objects from corruption。

    下面给出一个可变对象的类,从这个例子引导出不可变对象。这样可以对比出不可变对象的优势。

(一)           同步类的例子

类SynchronizedRGB,是一个代表颜色的例子。每个对象的三个整数分别代表一个原色,然后一个string代表颜色名字。

 

 

public class SynchronizedRGB {

     // Values must be between 0 and 255.

     private int red;

     private int green;

     private int blue;

     private String name;

     private void check(int red, int green, int blue) {

         if (red < 0 || red > 255

              || green < 0 || green > 255

              || blue < 0 || blue > 255) {

              throw new IllegalArgumentException();

         }

     }

     public SynchronizedRGB(int red, int green, int blue, String name) {

         check(red, green, blue);

         this.red = red;

         this.green = green;

         this.blue = blue;

         this.name = name;

     }

     public void set(int red, int green, int blue, String name) {

         check(red, green, blue);

         synchronized (this) {

              this.red = red;

              this.green = green;

              this.blue = blue;

              this.name = name;

         }

     }

     public synchronized int getRGB() {

         return ((red << 16) | (green << 8) | blue);

     }

     public synchronized String getName() {

         return name;

     }

     public synchronized void invert() {

         red = 255 - red;

         green = 255 - green;

         blue = 255 - blue;

         name = "Inverse of " + name;

     }

}

SynchronizedRGB必须很小心的使用去避免不一致状态。假设,一个线程执行下面的代码:

SynchronizedRGB color =

    new SynchronizedRGB(0, 0, 0, "Pitch Black");

...

 

int myColorInt = color.getRGB();      //Statement 1

String myColorName = color.getName(); //Statement 2

如果另一个线程在statement1和statement2之间调用coler.set,myColerInt和myColorName将不一致。为了避免这情况发生,两个语句必须绑定在一起:

synchronized (color) {

    int myColorInt = color.getRGB();

    String myColorName = color.getName();

}

这种情况只可能发生在可变对象,对于不可变对象版本的SynchronizedRGB这不是一个问题。

 

(二)           定义不可变对象的策略

接下来的规则定义了创建不可变对象的简单策略。并非所有的“不可改变的”类要遵循这些规则。这并不是说这些类的创建者是草率的——他们有很好的理由相信他们创建的类构造之后不会被改变。但是这要做复杂的分析,不适合初学者。

1,不要提供“setter”方法——那些修改域或者域关联的对象的方法。

2,让所有域都是final和private

3,不允许子类覆盖方法。最简单的方法是把class定义成final。更复杂的方法是把构造方法定义成private,然后通过工程方法构建实例。

4,如果对象的域引用了可变对象,不允许这些对象改变:?不提供修改这些对象的方法。

?不要共享可变对象的引用。不要通过构造方法存储可变对象的引用;如果有必要,创建对象副本,存储副本的引用。同样,避免在方法中返回原对象,而是创建你的内部可变对象的副本。

按照以下步骤给SynchronizedRGB添加这个策略:

1,class有两个setter方法。第一个set方法,任意转换对象,在不可变版本里去掉。第二个invert方法,用创建一个新对象代替修改这个对象。

2,所有的域是private和final。

3,class被声明成final

4,只有一个域引用对象,这个对象是他自己。因此,不用考虑被包含的可变对象的改变。

做了这些,我们得到ImmutableRGB:

final public class ImmutableRGB {

     // Values must be between 0 and 255.

     final private int red;

     final private int green;

     final private int blue;

     final private String name;

     private void check(int red, int green, int blue) {

         if (red < 0 || red > 255|| green < 0 || green > 255|| blue < 0 || blue > 255) {

              throw new IllegalArgumentException();

         }

     }

     public ImmutableRGB(int red, int green, int blue, String name) {

         check(red, green, blue);

         this.red = red;

         this.green = green;

         this.blue = blue;

         this.name = name;

     }

     public int getRGB() {

         return ((red << 16) | (green << 8) | blue);

     }

     public String getName() {

         return name;

     }

     public ImmutableRGB invert() {

         return new ImmutableRGB(255 - red, 255 - green, 255 - blue, "Inverse of " + name);

     }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值