共享资源
你可以认为单线程程序是一个单独的实体在你的程序中移动,每个时间点只做一件事情。因为只有一个实体,你永远不会去想两个实体试着在同一时间使用同一资源的问题:像两个人站在同一位置的问题,同时从门穿过或同时讲话。
当并发时,就不是一个实体的问题了。但是你现在可能要处理两个或多个任务彼此交互的问题。如果你不阻止这个问题,你将会发现在同一时间两个任务试着访问同一个银行账户,让同一台打印机打印,修改相同的值。
不正确地访问资源
考虑下面的例子,当一个任务负责生成偶数,另一个任务消费这些数字。这里,消费数数字的任务仅仅是检查偶数的真实性。
首先我们定义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基础的人学习提高
JAVA思想中文版,CHM格式.
java think in java (英文第四版)至今为止 被认为是java教程之中权威作品之一
Think in java 源码构建编译
think in java 源码整理,应该算是比较全面的,有需要的朋友可以下下来看下
Think in java 的代码源码,里面很详细的习题详解
Think Data Structures in Java 英文azw3 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn删除
作者:贯穿本书,我试图在您的大脑里建立一个模型——或者说一个“知识结构”。这样可加深对语言的理解。若遇到难解之处,应学会把它填入这个模型的对应地方,然后自行演绎出答案。事实上,学习任何语言时,脑海里有...
ThinkSystem RAID 530-8i驱动forsever2016or2012
think in java 第四版 源码以及作业 eclipse版本 包含jar包 可以直接导入eclipse
Think-In-Java-Code Thinking In Java 书中源码以及课后练习代码(从第7章开始随着看书的进度一步步更新) 第七章 复用类 7.1 组合语法 7.2 继承语法 7.2.1 初始化基类 7.3 代理 7.4 结合使用组合和继承 7.4.1 确保...
1.11 Java和因特网 1.11.1 什么是Web? 1.11.2 客户端编程 1.11.3 服务器端编程 1.11.4 一个独立的领域:应用程序 1.12 分析和设计 1.12.1 不要迷失 1.12.2 阶段0:拟出一个计划 1.12.3 阶段1:要制作什么?...
这是java编程思想中的练习题,自己感觉不错,上传上去给大家分享~~~~~
Think in Java 作者的文章 精辟见解
720Think-VR全景-智慧景区-VR全景行业解决方案.docx720Think-VR全景-智慧景区-VR全景行业解决方案.docx720Think-VR全景-智慧景区-VR全景行业解决方案.docx720Think-VR全景-智慧景区-VR全景行业解决方案.docx720Think...
720Think-VR全景-智慧景区-VR全景行业解决方案.pdf720Think-VR全景-智慧景区-VR全景行业解决方案.pdf720Think-VR全景-智慧景区-VR全景行业解决方案.pdf720Think-VR全景-智慧景区-VR全景行业解决方案.pdf720Think-VR...
Think in java 教程 Think in java 教程
Think in Java(美)Bruce Eckel 著 陈昊鹏 译 引言 同人类任何语言一样,Java为我们提供了一种表达思想的方式。如操作得当,同其他方式相 比,随着问题变得愈大和愈复杂,这种表达方式的方便性和灵活性会显露无遗。 ...
抽象的进步 1.2 对象的接口 1.3 实现方案的隐藏 1.4 方案的重复使用 1.5 继承:重新使用接口 1.5.1 改善基础类 1.5.2 等价和类似关系 1.6 多形对象的互换使用 1.6.1 动态绑定 ...1.11 Java和因特网
学习think in java 时的第9章的例题及练习答案。 eclipse 工程包,运行可用!全自己敲的!