共享资源
你可以认为单线程程序是一个单独的实体在你的程序中移动,每个时间点只做一件事情。因为只有一个实体,你永远不会去想两个实体试着在同一时间使用同一资源的问题:像两个人站在同一位置的问题,同时从门穿过或同时讲话。
当并发时,就不是一个实体的问题了。但是你现在可能要处理两个或多个任务彼此交互的问题。如果你不阻止这个问题,你将会发现在同一时间两个任务试着访问同一个银行账户,让同一台打印机打印,修改相同的值。
不正确地访问资源
考虑下面的例子,当一个任务负责生成偶数,另一个任务消费这些数字。这里,消费数数字的任务仅仅是检查偶数的真实性。
首先我们定义EvenChecker,这个消费的任务,因为它要在接下来的例子里重用。为了将EvenChecker从我们将要检查的各种类型的生成器中解耦出来,我们将要创建一个抽象类IntGenerator,它包含EvenChecker必须知道的最少的方法:它有一个next()方法并且可以取消。这个类不去实现泛型,因为它必须产生一个int,而泛型不支持原始类型。
public abstract class IntGenerator {
private volatile boolean canceled = false;
public abstract int next();
// Allow this to be canceled:
public void cancel() {
canceled = true;
}
public boolean isCanceled() {
return canceled;
}
}
IntCenerator有一个改变boolean canceled标志的cancel()方法和查看这个对象是否已经被取消的isCanceled()方法。因为canceled标志是播哦lean类型,它是原子的,意味着简单的操作像赋值和返回不会被中断,所以你不会看到这个值处于这些简单操作的中间状态。这个canceled标志也设置为volatile为了确保多个线程之间的可见性。在这章的后面你将会了解原子性和可见性。
任何IntGenerator可以在被下面的EvenChecker所测试:
public class EvenChecker implements Runnable {
private IntGenerator generator;
private final int id;
public EvenChecker(IntGenerator g, int ident) {
generator = g;
id = ident;
}
public void run() {
while (!generator.isCanceled()) {
int val = generator.next();
if (val % 2 != 0) {
System.out.println(val + " not even!");
generator.cancel(); // Cancels all EvenCheckers
}
}
}
// Test any type of IntGenerator:
public static void test(IntGenerator gp, int count) {
System.out.println("Press Control-C to exit");
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < count; i++)
exec.execute(new EvenChecker(gp, i));
exec.shutdown();
}
// Default value for count:
public static void test(IntGenerator gp) {
test(gp, 10);
}
}
要注意这个Class中可以被canceled的实例IntGenerator不是Runnable的。反而,EvenChecker却是Runnable的,它用来测试canceled状态的IntGenerator类却在它的run()方法里。
这种方式,这些共享共用资源(IntGenerator)的任务观察这个资源的信号去决定是否终止执行。这样会终止所谓的竞争条件,在那里,两个或多个任务竞争着去响应这个条件,因此产生冲突或者产生不一致的结果。你必须小心地考虑和防止所有可能并发系统可能崩溃的方式。例如,一个任务可能依赖于另一个任务,因为任务的停止顺序是没有保证的。这里 ,通过使任务依赖于非任务,我们消除了潜在的竞争条件。
test()方法建立并通过启动一些使用相同IntGenerator的EvenChecker任务来执行任何IntGenerator类型的测试。如果IntGenerator产生失败,test()将会报告并返回;否则,你必须使用Control-C来终止它。
我们看到的第一个IntGenerator有一个next()方法产生一系列偶数:
public class EvenGenerator extends IntGenerator {
private int currentEvenValue = 0;
public int next() {
++currentEvenValue; // Danger point here!
++currentEvenValue;
return currentEvenValue;
}
public static void main(String[] args) {
EvenChecker.test(new EvenGenerator());
}
}
可能发生这种情况,一个任务在另一个任务刚执行完第一个currentEvenValue的增加而没有执行第二个增值操作后调用call()。这使得值进入不正确的状态。为了证明这个可以发生,EvenChecker.test()创建一组EventChecker对象来不断地读取EvenGenerator产生的数据并测试它们是否是偶数。如果不是,报告错误并且终止程序。
这个程序将最终失败,因为EventChecker任务会访问EvenGenerator处于不正确状态的信息。然而,在EvenGenerator 完成多次循环前, 程序可能不会检查到这个问题,循环次数依赖于你操作系统和其他的实现细节。如果你想快些地看到失败,可以将yield()放到第一和第二个增值语句之间。这是多线程程序问题的一部分—--如果失败的概率非常低,即使有缺陷存在,程序可以看起来是正确的。
还有重要的一点需要知道,增值操作本身需要多步,并且任务可以通过线程机制在增值的中间状态被挂起。--就是说,在Java中,增值操作不是原子操作。所以一个简单的增值操作在没有保护的情况也是不安全的。
分享到:
相关推荐
好书共享, 一本不错的java入门书籍。 已看过几次。希望大家积极共享。
《Think in Java》是Bruce Eckel的经典著作,它为学习Java编程提供了一套全面而深入的教程。这个压缩包文件“thinkinjava源码-think-in-java”包含了该书中的示例源代码,对应的是“Think in Java”的开源版本,这...
为了防止数据竞争和不一致,需要使用同步机制来控制对共享资源的访问。《Think in Java》介绍了多种同步技术,包括但不限于: - **synchronized关键字**:用于同步方法或同步块,确保同一时间只有一个线程可以访问被...
综上所述,《Think in Java》这本书深入浅出地讲解了Java的核心概念和技术细节,包括构建器的特殊性质、`finalize()`方法在资源管理中的角色、`this`关键字的应用以及对象初始化的流程。通过对这些关键知识点的理解...
7. **共享资源的访问**:并发访问共享资源可能导致竞态条件,Java提供了`synchronized`关键字和`Lock`接口来保证同步。 8. **原子类**:Java 5引入的`AtomicInteger`、`AtomicLong`等类提供了原子操作,保证在多...
14.2.2 Java如何共享资源 14.2.3 回顾Java Beans 14.3 堵塞 14.3.1 为何会堵塞 14.3.2 死锁 14.4 优先级 14.4.1 线程组 14.5 回顾runnable 14.5.1 过多的线程 14.6 总结 14.7 练习 第15章 网络编程 ...
《Think in Pattern》一书由Bruce Eckel撰写,是一本专注于设计模式的深入探讨与实践指南。本书旨在帮助读者理解并应用设计模式于Java编程之中,通过实例解析,让复杂的问题变得易于理解和解决。 设计模式是软件...
这个压缩包文件"Think-in-java-source-Thinking-in-java:Java编程思想源码及习题!"提供了该书第四版中的源码实例,便于读者在IntelliJ IDEA或Eclipse等开发环境中直接使用和学习。 1. **Java编程基础** - **类与...
它常用于控制资源的共享,如线程池、缓存、对话框等。 3. 抽象工厂模式(Abstract Factory Pattern):抽象工厂模式提供一个创建对象族的接口,而无需指定其具体类。这在处理跨平台或者跨框架的代码时非常有用。 4...
本人刚在新华书店重金买的 JAVA 编程思想 配套光盘 共423M 完整共享 由于上传大小限制,共13parts 一起下载后解压就OK!
Bruce Eckel是著名的计算机科学家,以其撰写的“Think in”系列而闻名于世,其中包括《Think in Java》、《Think in C++》、《Think in Python》等多部编程著作。这些书籍深受程序员喜爱,并获得了广泛的好评。 ###...
《编程思想源码及答案笔记》是一份深入探讨Java编程技术的宝贵资源,它基于《Think in Java》这本书,该书由Bruce Eckel撰写,是许多程序员学习Java的首选教材。这份笔记结合了书中的理论知识与实际源码,旨在帮助...
在浏览《Thingking in Java》(第一版)时,你是不是觉得好象这还是一本 Java 基础语言书籍?但又不纯粹是,因为这本书的作 者将面向对象的思想巧妙的融合在 Java 的具体技术上,潜移默化的让你感觉到了一种新的语言...