如果一个对象在构造之后不可改变,那么这个对象就是不可变对象。不可变对象被广泛认同的作用是建立简单、可靠代码的万全之策。
不可变对象在并发应用程序中特别有用,因为他们不能被修改,他们不能发生线程冲突,或者发生不一致状态的读取。
程序员经常不心甘情愿的使用不可变对象,因为他们不能修改这个对象,只能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);
}
}
分享到:
相关推荐
Java并发编程规则:不可变对象永远是线程安全的 在Java并发编程中,了解不可变对象的概念对于编写线程安全的代码至关重要。不可变对象是指创建后状态不能被修改的对象,这类对象天生就是线程安全的。它们的常量...
在Java编程中,不可变对象是指一旦创建后其状态不能被修改的对象。这种对象模式在多线程环境和频繁对象创建的场景下,提供了线程安全保证,减少了内存开销,并提高了代码的可维护性。本文将详细介绍如何在Java中创建...
- 使用并发工具而非手工同步,如可能的话,优先选择不可变对象。 7. **Java内存模型** - **JMM(Java Memory Model)** 规定了线程如何访问和修改共享变量,以及对这些操作的排序规则,以保证多线程环境下的正确...
- **不可变对象**:介绍如何设计不可变对象以提高代码的安全性和效率。 - **锁分离**:讲解锁分离技术,以及如何通过减少锁的竞争来提高程序性能。 - **无锁编程**:探讨无锁编程的基本原理和技术细节,包括使用原子...
3.4.2 示例:使用Volatile类型来发布不可变对象 3.5 安全发布 3.5.1 不正确的发布:正确的对象被破坏 3.5.2 不可变对象与初始化安全性 3.5.3 安全发布的常用模式 3.5.4 事实不可变对象 3.5.5 可变对象 3.5.6 ...
- **定义**: 不可变字段在对象创建后被设置一次且不可更改。 - **特性**: 创建结束时,若对象被安全发布,则所有线程都可以获取到final字段在构造过程中设置的值,即使没有`synchronized`关键字。 #### 三、保护...
Java并发编程是Java开发中的重要领域,特别是在多核处理器和分布式系统中,高效地利用并发可以极大地提升程序的性能和响应速度。这份“java并发编程内部分享PPT”显然是一个深入探讨这一主题的资料,旨在帮助开发者...
4. **线程池**:`ExecutorService`是Java并发框架的核心,它管理一组可重用线程,有效地调度和执行任务。`ThreadPoolExecutor`是其最常见的实现,允许自定义线程池参数。 5. **并发工具类**:如`CountDownLatch`、`...
- **不可变对象**:创建不可变对象是一种简化并发编程的有效方式。书中解释了不可变对象的概念及其在Java中的实现方法。 - **原子变量**:原子变量提供了一种简单的方式来更新基本类型的值,而无需显式同步。书中...
- 使用不可变对象。 - 避免过度同步。 - 优先使用并发工具类而不是自建同步机制。 - 对于长时间运行的任务,考虑使用线程池。 以上内容涵盖了Java并发编程的多个关键点,从基础知识到高级技巧,希望对你理解和...
- 不可变对象(Immutable Objects):一旦创建就不能被修改的对象,天然线程安全。 学习Java并发编程,重点在于理解线程如何协同工作,以及如何确保并发执行的正确性和高效性。通过深入掌握Java并发API,可以为大型...
Java并发编程是Java开发者必须掌握的关键技能之一,它涉及到如何在多线程环境中高效、安全地执行程序。并发编程能够充分利用多核处理器的计算能力,提高应用程序的响应速度和整体性能。《Java编程并发实战》这本书是...
3. **锁**:Java并发库中的`java.util.concurrent.locks`包提供了更高级的锁机制,如可重入锁(`ReentrantLock`)、读写锁(`ReadWriteLock`)和条件变量(`Condition`),这些工具允许更灵活的控制并发访问。 4. **并发...
本资料“Java并发编程设计原则和模式”深入探讨了如何在Java环境中有效地进行并发处理,以充分利用系统资源并避免潜在的并发问题。 一、并发编程基础 并发是指两个或多个操作在同一时间段内执行,但并不意味着这些...
- **不可变对象**:一旦被创建就无法改变其状态的对象,在多线程环境下更加安全。 - **volatile变量**:用于确保变量的可见性和一定程度上的有序性。 #### 3.3 原子操作与原子类 - **原子操作**:在单个处理器上...
3.4.2 示例:使用Volatile类型来发布不可变对象 3.5 安全发布 3.5.1 不正确的发布:正确的对象被破坏 3.5.2 不可变对象与初始化安全性 3.5.3 安全发布的常用模式 3.5.4 事实不可变对象 3.5.5 可变对象 3.5.6 ...
书中会讲解什么是线程不安全,并给出避免线程安全问题的策略,如使用线程局部变量(ThreadLocal)和不可变对象。 3. **并发工具** Java并发库提供了丰富的工具类,如ExecutorService、Semaphore、CountDownLatch和...
Java并发编程是Java开发中的重要领域,特别是在大型分布式系统、多线程应用和服务器端程序设计中不可或缺。这个资源包“Java并发编程从入门到精通源码.rar”显然是为了帮助开发者深入理解并掌握这一关键技能。它包含...