不可变对象(Immutable Objects)(Concurrency tutorial 6)
不可变对象(Immutable Objects)
如果一个对象的状态在其创建之后不能被改变,那我们就说它是不可变对象。在多线程编程中,最大程度地使用不可变对象可以实现简单又可靠的代码。
不可变对象在并发应用中特别有用。因为它们不会改变状态,它们在遇到线程干扰和不一致访问时也不会出错(译注:因为每个线程在试图改变一个对象时,实际上是得到了该对象在最新状态下的拷贝,例如String就是不可变对象)。
程序员经常不愿使用不可变对象,因为他们担心拷贝对象会降低性能。实际上,创建对象的资源耗费常被高估(overestimated),实际上这样的资源耗费完全可以被不可变对象提高的效率抵消掉。使用不可变对象可以降低因垃圾回收产生的对象管理开支,消除为保护可变对象不被污染的额外代码。
下面几个小节里将创建一个状态可变的类,然后演化成一个状态不可变的类。以此描述转换要遵守的规则以及不可变对象相对于可变对象的优势。
一个同步类的例子
SychronizedRGB类定义了表示颜色对象的集合。每一个对象代表一种颜色,每一种颜色用三个表示基本色的整数和一个描述颜色名称的字符串表示。
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 color = new SynchronizedRGB(0, 0, 0, "Pitch Black");...int myColorInt = color.getRGB(); //Statement 1String myColorName = color.getName(); //Statement 2
synchronized (color) { int myColorInt = color.getRGB(); String myColorName = color.getName();} 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); }}