按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
〃d。isDaemon() = 〃 + d。isDaemon());
// Allow the daemon threads to finish
// their startup processes:
BufferedReader stdin =
new BufferedReader(
new InputStreamReader(System。in));
System。out。println(〃Waiting for CR〃);
try {
stdin。readLine();
} catch(IOException e) {}
}
} ///:~
Daemon 线程可将自己的Daemon 标记设置成“真”,然后产生一系列其他线程,而且认为它们也具有 Daemon
属性。随后,它进入一个无限循环,在其中调用yield(),放弃对其他进程的控制。在这个程序早期的一个
版本中,无限循环会使 int计数器增值,但会使整个程序都好象陷入停顿状态。换用 yield()后,却可使程
序充满“活力”,不会使人产生停滞或反应迟钝的感觉。
一旦main()完成自己的工作,便没有什么能阻止程序中断运行,因为这里运行的只有 Daemon 线程。所以能
看到启动所有Daemon 线程后显示出来的结果,System。in 也进行了相应的设置,使程序中断前能等待一个回
车。如果不进行这样的设置,就只能看到创建 Daemon 线程的一部分结果(试试将readLine()代码换成不同
长度的 sleep()调用,看看会有什么表现)。
14。2 共享有限的资源
可将单线程程序想象成一种孤立的实体,它能遍历我们的问题空间,而且一次只能做一件事情。由于只有一
个实体,所以永远不必担心会有两个实体同时试图使用相同的资源,就象两个人同时都想停到一个车位,同
时都想通过一扇门,甚至同时发话。
进入多线程环境后,它们则再也不是孤立的。可能会有两个甚至更多的线程试图同时同一个有限的资源。必
须对这种潜在资源冲突进行预防,否则就可能发生两个线程同时访问一个银行帐号,打印到同一台计算机,
以及对同一个值进行调整等等。
14。2。1 资源访问的错误方法
现在考虑换成另一种方式来使用本章频繁见到的计数器。在下面的例子中,每个线程都包含了两个计数器,
它们在 run()里增值以及显示。除此以外,我们使用了 Watcher 类的另一个线程。它的作用是监视计数器,
检查它们是否保持相等。这表面是一项无意义的行动,因为如果查看代码,就会发现计数器肯定是相同的。
但实际情况却不一定如此。下面是程序的第一个版本:
//: Sharing1。java
// Problems with resource sharing while threading
import java。awt。*;
import java。awt。event。*;
import java。applet。*;
class TwoCounter extends Thread {
private boolean started = false;
private TextField
t1 = new TextField(5);
t2 = new TextField(5);
private Label l =
new Label(〃count1 == count2〃);
private int count1 = 0; count2 = 0;
// Add the display ponents as a panel
499
…………………………………………………………Page 501……………………………………………………………
// to the given container:
public TwoCounter(Container c) {
Panel p = new Panel();
p。add(t1);
p。add(t2);
p。add(l);
c。add(p);
}
public void start() {
if(!started) {
started = true;
super。start();
}
}
public void run() {
while (true) {
t1。setText(Integer。toString(count1++));
t2。setText(Integer。toString(count2++));
try {
sleep(500);
} catch (InterruptedException e){}
}
}
public void synchTest() {
Sharing1。incrementAccess();
if(count1 != count2)
l。setText(〃Unsynched〃);
}
}
class Watcher extends Thread {
private Sharing1 p;
public Watcher(Sharing1 p) {
this。p = p;
start();
}
public void run() {
while(true) {
for(int i = 0; i 《 p。s。length; i++)
p。s'i'。synchTest();
try {
sleep(500);
} catch (InterruptedException e){}
}
}
}
public class Sharing1 extends Applet {
TwoCounter'' s;
private static int accessCount = 0;
private static TextField aCount =
new TextField(〃0〃; 10);
500
…………………………………………………………Page 502……………………………………………………………
public static void incrementAccess() {
accessCount++;
aCount。setText(Integer。toString(accessCount));
}
private Button
start = new Button(〃Start〃);
observer = new Button(〃Observe〃);
private boolean isApplet = true;
private int numCounters = 0;
private int numObservers = 0;
public void init() {
if(isApplet) {
numCounters =
Integer。parseInt(getParameter(〃size〃));
numObservers =
Integer。parseInt(
getParameter(〃observers〃));
}
s = new TwoCounter'numCounters';
for (int i = 0; i 《 s。length; i++)
s'i' = new TwoCounter(this);
Panel p = new Panel();
start。addActionListener(new StartL());
p。add(start);
observer。addActionListener(new ObserverL());
p。add(observer);
p。add(new Label(〃Access Count〃));
p。add(aCount);
add(p);
}
class StartL implements ActionListener {
public void actionPerformed(ActionEvent e) {
for(int i = 0; i 《 s。length; i++)
s'i'。start();
}
}
class ObserverL implements ActionListener {
public void actionPerformed(ActionEvent e) {
for(int i = 0; i 《 numObservers; i++)
new Watcher(Sharing1。this);
}
}
public static void main(String'' args) {
Sharing1 applet = new Sharing1();
// This isn't an applet; so set the flag and
// produce the parameter values from args:
applet。isApplet = false;
applet。numCounters =
(args。length == 0 ? 5 :
Integer。parseInt(args'0'));
applet。numObservers =
(args。length 《 2 ? 5 :
501
…………………………………………………………Page 503……………………………………………………………
Integer。parseInt(args'1'));
Frame aFrame = new Frame(〃Sharing1〃);
aFrame。addWindowListener(
new WindowAdapter() {