多線程(6): Java Threads例子的一個問題
看到《Java Threads》第5章,介紹了JDK 1.5新加的一些所謂原子類(Atomic Classes),總感覺有點(diǎn)為原子而原子,實(shí)際操作中,又有多少人會為了少許的性能提升而刻意去用這些別扭的操作而放棄直觀的synchronize關(guān) 鍵字或者Lock類呢?不過,這里不是想討論這個,而是當(dāng)其用Atomic Classes來改造它的打字程序后,解釋用原子類只是保證類似遞增、遞減、賦值等操作的原子性,而不能保證其所在的方法一定是線程安全的,然后說,有可 能按鍵事件的處理可能需要等待resetScore()處理完才能執(zhí)行,而這會導(dǎo)致錯誤的評分(被當(dāng)成多敲了鍵)。由于前幾章的內(nèi)容相對比較簡單易懂,所 以也沒有很仔細(xì)的運(yùn)行那些例子。這里為了驗(yàn)證一下,就運(yùn)行了一下第4章的例子,然后發(fā)現(xiàn),基本上第一次的評分總是錯的。這就引起了我的注意,因?yàn)椋话闱? 況下,如果是race condition導(dǎo)致的錯誤是很難重現(xiàn)的,這么明顯的錯誤很可能是程序邏輯上的錯誤。仔細(xì)看了一下代碼,發(fā)現(xiàn)在start按鈕的事件處理方法里,有下面 這樣一段代碼:startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
displayCanvas.setDone(false);
producer.setDone(false);
startButton.setEnabled(false);
stopButton.setEnabled(true);
feedbackCanvas.setEnabled(true);
feedbackCanvas.requestFocus();
score.resetScore();
}
});
注意重置成績的調(diào)用放在了最后,此時,隨機(jī)生成字符的線程應(yīng)該被喚醒并產(chǎn)生了第一個字符,然后,resetScore()將需要輸入的字符又設(shè)成了-1,
所以,當(dāng)你第一次輸入字符時,總是被認(rèn)為是多擊了一次鍵而扣1分:(。既然這樣,那停止然后再啟動也應(yīng)該會發(fā)生這個錯誤啊。而事實(shí)上的確是這樣。我想,這
不應(yīng)該看做是race
condition吧,有什么樣的同步技術(shù)能夠避免這個問題呢?除非另外弄個標(biāo)志,當(dāng)成績沒有被重置前,不能產(chǎn)生第一個字符。當(dāng)然,這是不需要的,只要將
score.resetScore()放到第一句就可以了。public void actionPerformed(ActionEvent evt) {
displayCanvas.setDone(false);
producer.setDone(false);
startButton.setEnabled(false);
stopButton.setEnabled(true);
feedbackCanvas.setEnabled(true);
feedbackCanvas.requestFocus();
score.resetScore();
}
});
然 后又運(yùn)行了第3章的例子,發(fā)現(xiàn)基本上沒有這個問題。難道第3章的代碼是正確的?打開源代碼一看,重置成績的方法還是放在最后,那這里為什么又是正確的呢? 我想,大約是第3章的例子中,每次點(diǎn)擊start按鈕,都重新創(chuàng)建一個線程對象的原因吧。由于創(chuàng)建對象和初始化線程需要一定的時間,剛好給了主線程重置成 績的機(jī)會。
不知道作者有意為之呢,還是疏忽,不過,這樣的錯誤不能算是race condition的例子。
posted on 2006-03-09 23:00 Vincent.Chen 閱讀(112) 評論(0) 編輯 收藏 所屬分類: Java