`

Think in java 846-848 共享资源

阅读更多
共享资源
你可以认为单线程程序是一个单独的实体在你的程序中移动,每个时间点只做一件事情。因为只有一个实体,你永远不会去想两个实体试着在同一时间使用同一资源的问题:像两个人站在同一位置的问题,同时从门穿过或同时讲话。
当并发时,就不是一个实体的问题了。但是你现在可能要处理两个或多个任务彼此交互的问题。如果你不阻止这个问题,你将会发现在同一时间两个任务试着访问同一个银行账户,让同一台打印机打印,修改相同的值。
不正确地访问资源
   考虑下面的例子,当一个任务负责生成偶数,另一个任务消费这些数字。这里,消费数数字的任务仅仅是检查偶数的真实性。
首先我们定义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中,增值操作不是原子操作。所以一个简单的增值操作在没有保护的情况也是不安全的。
分享到:
评论

相关推荐

    think-in-java

    好书共享, 一本不错的java入门书籍。 已看过几次。希望大家积极共享。

    thinkinjava源码-think-in-java:Java思维的源代码

    《Think in Java》是Bruce Eckel的经典著作,它为学习Java编程提供了一套全面而深入的教程。这个压缩包文件“thinkinjava源码-think-in-java”包含了该书中的示例源代码,对应的是“Think in Java”的开源版本,这...

    thinkin java里面对多线程详细讲解

    为了防止数据竞争和不一致,需要使用同步机制来控制对共享资源的访问。《Think in Java》介绍了多种同步技术,包括但不限于: - **synchronized关键字**:用于同步方法或同步块,确保同一时间只有一个线程可以访问被...

    Think in java读书笔记

    综上所述,《Think in Java》这本书深入浅出地讲解了Java的核心概念和技术细节,包括构建器的特殊性质、`finalize()`方法在资源管理中的角色、`this`关键字的应用以及对象初始化的流程。通过对这些关键知识点的理解...

    Thinking in Java知识点总结

    7. **共享资源的访问**:并发访问共享资源可能导致竞态条件,Java提供了`synchronized`关键字和`Lock`接口来保证同步。 8. **原子类**:Java 5引入的`AtomicInteger`、`AtomicLong`等类提供了原子操作,保证在多...

    Think in Java(中文版)chm格式

    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

    《Think in Pattern》一书由Bruce Eckel撰写,是一本专注于设计模式的深入探讨与实践指南。本书旨在帮助读者理解并应用设计模式于Java编程之中,通过实例解析,让复杂的问题变得易于理解和解决。 设计模式是软件...

    thinkinjava源码-Thinking-in-java:Java编程思想源码及习题!

    这个压缩包文件"Think-in-java-source-Thinking-in-java:Java编程思想源码及习题!"提供了该书第四版中的源码实例,便于读者在IntelliJ IDEA或Eclipse等开发环境中直接使用和学习。 1. **Java编程基础** - **类与...

    java设计模式之面向对象的思想(think in OO(Object Oriented))

    它常用于控制资源的共享,如线程池、缓存、对话框等。 3. 抽象工厂模式(Abstract Factory Pattern):抽象工厂模式提供一个创建对象族的接口,而无需指定其具体类。这在处理跨平台或者跨框架的代码时非常有用。 4...

    JAVA 编程思想 配套光盘 共423M 12/13

    本人刚在新华书店重金买的 JAVA 编程思想 配套光盘 共423M 完整共享 由于上传大小限制,共13parts 一起下载后解压就OK!

    C#编程思想pdf版

    Bruce Eckel是著名的计算机科学家,以其撰写的“Think in”系列而闻名于世,其中包括《Think in Java》、《Think in C++》、《Think in Python》等多部编程著作。这些书籍深受程序员喜爱,并获得了广泛的好评。 ###...

    thinkInJava:编程思想源码及答案笔记

    《编程思想源码及答案笔记》是一份深入探讨Java编程技术的宝贵资源,它基于《Think in Java》这本书,该书由Bruce Eckel撰写,是许多程序员学习Java的首选教材。这份笔记结合了书中的理论知识与实际源码,旨在帮助...

    二十三种设计模式【PDF版】

    在浏览《Thingking in Java》(第一版)时,你是不是觉得好象这还是一本 Java 基础语言书籍?但又不纯粹是,因为这本书的作 者将面向对象的思想巧妙的融合在 Java 的具体技术上,潜移默化的让你感觉到了一种新的语言...

Global site tag (gtag.js) - Google Analytics