- 写在前面的话
- 引言
- 第 1 章 对象入门
- 第 2 章 一切都是对象
- 第 3 章 控制程序流程
- 第 4 章 初始化和清除
- 第 5 章 隐藏实施过程
- 第 6 章 类再生
- 第 7 章 多形性
- 第 8 章 对象的容纳
- 第 9 章 违例差错控制
- 第 10 章 Java IO 系统
- 第 11 章 运行期类型鉴定
- 第 12 章 传递和返回对象
- 第 十三 章 创建窗口和程序片
- 第 14 章 多线程
- 第 15 章 网络编程
- 第 16 章 设计范式
- 第 17 章 项目
- 附录 A 使用非 JAVA 代码
- 附录 B 对比 C++和 Java
- 附录 C Java 编程规则
- 附录 D 性能
- 附录 E 关于垃圾收集的一些话
- 附录 F 推荐读物
14.5.1 过多的线程
有些时候,我们会发现 ColorBoxes 几乎陷于停顿状态。在我自己的机器上,这一情况在产生了 10×10 的网格之后发生了。为什么会这样呢?自然地,我们有理由怀疑 AWT 对它做了什么事情。所以这里有一个例子能够测试那个猜测,它产生了较少的线程。代码经过了重新组织,使一个 Vector 实现了 Runnable,而且那个 Vector 容纳了数量众多的色块,并随机挑选一些进行更新。随后,我们创建大量这些 Vector 对象,数量大致取决于我们挑选的网格维数。结果便是我们得到比色块少得多的线程。所以假如有一个速度的加快,我们就能立即知道,因为前例的线程数量太多了。如下所示:
//: ColorBoxes2.java // Balancing thread use import java.awt.*; import java.awt.event.*; import java.util.*; class CBox2 extends Canvas { private static final Color[] colors = { Color.black, Color.blue, Color.cyan, Color.darkGray, Color.gray, Color.green, Color.lightGray, Color.magenta, Color.orange, Color.pink, Color.red, Color.white, Color.yellow }; private Color cColor = newColor(); private static final Color newColor() { return colors[ (int)(Math.random() * colors.length) ]; } void nextColor() { cColor = newColor(); repaint(); } public void paint(Graphics g) { g.setColor(cColor); Dimension s = getSize(); g.fillRect(0, 0, s.width, s.height); } } class CBoxVector extends Vector implements Runnable { private Thread t; private int pause; public CBoxVector(int pause) { this.pause = pause; t = new Thread(this); } public void go() { t.start(); } public void run() { while(true) { int i = (int)(Math.random() * size()); ((CBox2)elementAt(i)).nextColor(); try { t.sleep(pause); } catch(InterruptedException e) {} } } } public class ColorBoxes2 extends Frame { private CBoxVector[] v; public ColorBoxes2(int pause, int grid) { setTitle("ColorBoxes2"); setLayout(new GridLayout(grid, grid)); v = new CBoxVector[grid]; for(int i = 0; i < grid; i++) v[i] = new CBoxVector(pause); for (int i = 0; i < grid * grid; i++) { v[i % grid].addElement(new CBox2()); add((CBox2)v[i % grid].lastElement()); } for(int i = 0; i < grid; i++) v[i].go(); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } public static void main(String[] args) { // Shorter default pause than ColorBoxes: int pause = 5; int grid = 8; if(args.length > 0) pause = Integer.parseInt(args[0]); if(args.length > 1) grid = Integer.parseInt(args[1]); Frame f = new ColorBoxes2(pause, grid); f.setSize(500, 400); f.setVisible(true); } } ///:~
在 ColorBoxes2 中,我们创建了 CBoxVector 的一个数组,并对其初始化,使其容下各个 CBoxVector 网格。每个网格都知道自己该“睡眠”多长的时间。随后为每个 CBoxVector 都添加等量的 Cbox2 对象,而且将每个 Vector 都告诉给 go(),用它来启动自己的线程。
CBox2 类似 CBox——能用一种随机选择的颜色描绘自己。但那就是 CBox2 能够做的全部工作。所有涉及线程的处理都已移至 CBoxVector 进行。
CBoxVector 也可以拥有继承的 Thread,并有一个类型为 Vector 的成员对象。这样设计的好处就是 addElement() 和 elementAt() 方法可以获得特定的参数以及返回值类型,而不是只能获得常规 Object(它们的名字也可以变得更短)。然而,这里采用的设计表面上看需要较少的代码。除此以外,它会自动保留一个 Vector 的其他所有行为。由于 elementAt() 需要大量进行“封闭”工作,用到许多括号,所以随着代码主体的扩充,最终仍有可能需要大量代码。
和以前一样,在我们实现 Runnable 的时候,并没有获得与 Thread 配套提供的所有功能,所以必须创建一个新的 Thread,并将自己传递给它的构建器,以便正式“启动”——start()——一些东西。大家在 CBoxVector 构建器和 go() 里都可以体会到这一点。run() 方法简单地选择 Vector 里的一个随机元素编号,并为那个元素调用 nextColor(),令其挑选一种新的随机颜色。
运行这个程序时,大家会发现它确实变得更快,响应也更迅速(比如在中断它的时候,它能更快地停下来)。而且随着网格尺寸的壮大,它也不会经常性地陷于“停顿”状态。因此,线程的处理又多了一项新的考虑因素:必须随时检查自己有没有“太多的线程”(无论对什么程序和运行平台)。若线程太多,必须试着使用上面介绍的技术,对程序中的线程数量进行“平衡”。如果在一个多线程的程序中遇到了性能上的问题,那么现在有许多因素需要检查:
(1) 对 sleep,yield() 以及/或者 wait() 的调用足够多吗?
(2) sleep() 的调用时间足够长吗?
(3) 运行的线程数是不是太多?
(4) 试过不同的平台和 JVM 吗?
象这样的一些问题是造成多线程应用程序的编制成为一种“技术活”的原因之一。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论