并发编程中的对象访问限制技术
立即解锁
发布时间: 2025-08-17 02:17:20 阅读量: 1 订阅数: 3 

### 并发编程中的对象访问限制技术
#### 1. 内存一致性模型与访问限制概述
随着多处理器和多线程程序变得越来越普遍,它们之间的交互也越来越受到关注,内存一致性模型正受到越来越多的关注。至少在锁定方面,Java 内存模型最接近释放一致性模型家族。
访问限制(Confinement)是一种利用封装技术来保证在同一时间最多只有一个活动可以访问给定对象的方法。它通过静态方式确保对象的可访问性对单个线程是唯一的,而无需在每次访问时依赖动态锁定。主要策略是定义方法和类,建立无泄漏的所有权域,保证只有一个线程或同一时间只有一个线程可以访问受限对象。
判断对象引用是否会从方法中逃逸,有以下四个类别需要检查:
- 方法将引用作为参数传递给方法调用或对象构造函数。
- 方法将引用作为方法调用的返回值传递。
- 方法将引用记录在其他活动可以访问的字段中(最明显的情况是任何地方都可访问的静态字段)。
- 方法以任何上述方式释放另一个引用,而该引用又可以被遍历以访问原引用。
#### 2. 跨方法的访问限制
如果一个方法调用创建了一个对象并且不让它逃逸,那么可以确保没有其他线程会干扰该方法对该对象的使用。在局部作用域内隐藏访问是所有编程形式中常见的封装策略。这种技术可以扩展到一系列的方法调用。
例如,以下是一个使用 `java.awt.Point` 的类:
```java
class Plotter { // Fragments
// ...
public void showNextPoint() {
Point p = new Point();
p.x = computeX();
p.y = computeY();
display(p);
}
protected void display(Point p) {
// somehow arrange to show p.
}
}
```
在这个例子中,`showNextPoint` 方法创建了一个局部的 `Point` 对象。它只在尾调用中将 `Point` 对象传递给 `display` 方法,并且在这之后 `showNextPoint` 方法确保不再访问该对象。这是一种交接协议的示例,确保在任何给定时间,最多只有一个正在执行的方法可以访问一个对象。
##### 2.1 会话(Sessions)
许多交接序列被构造为会话,其中一些公共入口方法构造将被限制在一系列操作中的对象,这些操作构成一个服务。该入口方法还应负责在序列完成时所需的任何清理操作。
例如:
```java
class SessionBasedService { // Fragments
// ...
public void service() {
OutputStream output = null;
try {
output = new FileOutputStream("...");
doService(output);
} catch (IOException e) {
handleIOFailure();
} finally {
try { if (output != null) output.close(); }
catch (IOException ignore) {} // ignore exception in close
}
}
void doService(OutputStream s) throws IOException {
s.write(...);
// ... possibly more handoffs ...
}
}
```
通常,在 `finally` 子句中执行清理操作比依赖终结器(即重写 `Object.finalize`)更可取,因为 `finally` 子句能更有力地保证清理操作的执行时间,有助于节省可能稀缺的资源,如文件。
##### 2.2 替代协议
如果一个方法在调用后必须访问一个对象或必须进行多次调用,尾调用交接就不适用了。对于这种情况,有以下几种选择:
- **调用者复制(Caller copies)**:当传递的对象代表数据值(如点),且对象标识不重要时,调用者可以复制对象供接收者使用。例如,将 `display(p);` 替换为 `display(new Point(p.x, p.y));`。
- **接收者复制(Receiver copies)**:如果一个方法对作为参数传递的对象引用的使用约束一无所知,并且对象标识不重要,它可以保守地复制对象供自己本地使用。例如,在 `display` 方法的第一行添加 `Point localPoint = new Point(p.x, p.y);`。
- **使用标量参数(Using scalar arguments)**:通过不传递引用,而是传递标量参数,为接收者提供足够的信息来构造对象,可以消除调用者和接收者责任的不确定性。例如,将 `display` 方法重新参数化为 `protected void display(int xcoord, int ycoord) { ... }`,并调用 `display(p.x, p.y);`。
- **信任(Trust)**:接收者(或其作者)可以承诺不修改或传递通过引用参数可访问的对象,并确保在任何下游调用中都不会出现不必要的访问。
下面是这些替代协议的对比表格:
| 协议类型 | 操作方式 | 适用场景 |
| --- | --- | --- |
| 调用者复制 | 调用者复制对象供接收者使用 | 对象标识不重要,传递数据值 |
| 接收者复制 | 接收者复制对象供本地使用 | 对对象引用使用约束一无所知,对象标识不重要 |
| 使用标量参数 | 传递标量参数供接收者构造对象 | 消除调用者和接收者责任的不确定性 |
| 信任 | 接收者承诺不修改或传递对象 | 接收者可保证无不必要访问 |
#### 3. 线程内的访问限制
基于线程的访问限制技术扩展了跨方法的访问限制技术。最简单且通常最好的技术是使用每个会话一个线程的设计,这与基于会话的访问限制类似。
例如:
```java
class ThreadPerSessionBasedService { // fragments
// ...
public void service() {
Runnable r = new Runnable() {
public void run() {
OutputStream output = null;
try {
```
0
0
复制全文
相关推荐










