诊断这种崩溃的一个辅助手段是捕捉由各种线程抛出的异常并在退出之前通知该问题的依赖线程。这正是我在清单 2 中所做的。
清单 2. 把错误通知给客户机线程的示例
import java.util.vector;
public class server2 extends thread {
client2 client;
int counter;
public server2(client2 _client) {
this.client = _client;
this.counter = 0;
}
public void run() {
try {
while (counter < 10) {
this.client.queue.addelement(new integer(counter));
counter++;
}
throw new runtimeexception("counter >= 10");
}
catch (exception e) {
this.client.interruptflag = true;
throw new runtimeexception(e.tostring());
}
}
public static void main(string[] args) {
client2 c = new client2();
server2 s = new server2(c);
c.start();
s.start();
}
}
class client2 extends thread {
vector queue;
boolean interruptflag;
public client2() {
this.queue = new vector();
this.interruptflag = false;
}
public void run() {
while (! interruptflag) {
if (! (queue.size() == 0)) {
processnextelement();
}
}
// processes whatever elements remain on the queue before exiting.
while (! (queue.size() == 0)) {
processnextelement();
}
system.out.flush();
}
private void processnextelement() {
object next = queue.elementat(0);
queue.removeelementat(0);
system.out.println(next);
}
}
处理被抛出的异常的其它选项可能是调用 system.exit。这个选项在程序的主线程发生崩溃而其它线程不管理任何临界资源的时候是有意义的。然而在其它情况下,这可能是危险的。例如,考虑这样一个示例,其它线程中的一个正在管理一个打开的文件。如果这是实际的情况,那么只是退出程序会导致资源泄漏。
即使在上面的简单示例中,在 server 线程中调用 system.exit 也会导致 client 未处理其队列上的任何剩余元素就退出。
事实上,就是这样的问题促使 sun 不建议线程的 stop 方法。由于强行停止一个线程会使资源陷入非一致状态,所以 stop 方法破坏了语言的安全性模型。
想了解 sun 的更多不建议理由,请参阅参考资料。
总结
这里是本周错误模式的总结:
模式:孤线程
症状:一个锁定多线程程序,它具有或不具有将堆栈跟踪打印到标准错误。
致因:多个程序线程一直等待来自某个线程的输入,而该线程在抛出一个未被捕捉的异常后就退出了。
治疗和预防措施:把异常处理代码放到主线程中以在崩溃来临之际通知依赖线程。
参考资料
参加本文的讨论论坛。
阅读关于为什么不建议 thread.stop 的 sun 的解释。
neel v. kumar 在他的文章“java 程序中的多线程”(developerworks,2000 年 3 月)中提供调试多线程 java 的途径。
peter haggar 的“优化 java 编程中的并发”(ibm partnerworld for developers)是一份优秀的白皮书,它讨论通过执行多线程来并发存取数据会导致的常见问题。
想获得编写多线程 java 程序的介绍,请参阅 alex roetter 的文章“编写多线程 java 应用程序”(developerworks,2001 年 2 月)。
想为您的 java 应用程序中的多线程问题获得技术帮助,请访问多线程 java 编程讨论论坛。
brian goetz 在他共三部分的系列轻松使用线程中处理困难的线程问题。
junit 主页提供讨论程序测试方法的很多有趣文章的链接,并提供 junit 的最新版本。
利用 java 调试教程(developerworks,2001 年 2 月),获取通用调试技术的帮助。
阅读 eric 所有诊断 java 代码的文章,其中多数着重讨论错误模式。
请在 developerworks java 技术专区查找更多的 java 参考资料。
关于作者
eric allen 从 cornell 大学获得计算机科学及数学的学士学位,并且是 rice 大学 java 编程语言小组的博士候选人。在回 rice 专心攻读学位前,eric 是 cycorp,inc. 的 java 开发者带头人。他还在 javaworld 上主持 java 初学者讨论论坛。他的研究包括在源程序和字节码级别上 java 语言的语义模型和静态分析工具开发。eric 还帮助开发 rice 的 nextgen 编程语言编译器,nextgen 是一个支持泛运行时类型的 java 扩展。可通过 eallen@cs.rice.edu 与 eric 联系。
闽公网安备 35060202000074号