java mousepress_Java线程原语弃用
為什么是線程停止不贊成?
因為它本質上是不安全的。停止線程會使其解鎖其鎖定的所有監視器。(當ThreadDeath異常在堆棧上傳播時,監視器將被解鎖。)如果以前受這些監視器保護的任何對象處于不一致狀態,其他線程現在可能會以不一致的狀態查看這些對象。據說這些物品被損壞了。當線程對損壞的對象進行操作時,可能會導致任意行為。這種行為可能是微妙的,很難被發現,也可能是被宣布的。與其他未經檢查的異常不同,ThreadDeath無聲地殺死線程;因此,用戶沒有警告他的程序可能已損壞。腐敗在實際損害發生后的任何時候都會顯現出來,甚至在未來的幾個小時或幾天內也是如此。
為什么是線程停止我不能捕獲ThreadDeath異常并修復損壞的對象嗎?
從理論上講,可能是這樣,但這會使編寫正確的多線程代碼的任務變得非常復雜。這項任務幾乎無法完成,原因有兩個:
1.線程幾乎可以在任何地方拋出ThreadDeath異常。所有同步的方法和塊都必須非常詳細地研究,記住這一點。
2.當從第一個線程(在catch或finally子句中)清除時,線程可以拋出第二個ThreadDeath異常。清理工作必須重復進行,直到成功為止。確保這一點的代碼將非常復雜。
總之,這是不實際的。
那如何線程停止(可丟棄的)?
除上述所有問題外,此方法還可用于生成目標線程未準備好處理的異常(包括如果沒有此方法,則線程不可能拋出的檢查異常)。例如,以下方法在行為上與Java的拋出操作相同,但避免了編譯器試圖確保調用方法聲明了它可能拋出的所有檢查異常:
static void sneakyThrow(Throwable t) {
Thread.currentThread().stop(t);
}
我應該用什么來代替線程停止?
大多數停止的用法應該被簡單地修改一些變量以指示目標線程應該停止運行的代碼所取代。目標線程應該定期檢查該變量,如果變量指示要停止運行,則應該以有序的方式從它的run方法返回。為了確保停止請求的快速通信,變量必須是易失性的(或者對變量的訪問必須是同步的)。例如,假設您的applet包含以下啟動、停止和運行方法:
private Thread blinker;
public void start() {
blinker = new Thread(this);
blinker.start();
}
public void stop() {
blinker.stop(); // UNSAFE!
}
public void run() {
while (true) {
try {
Thread.sleep(interval);
} catch (InterruptedException e){
}
repaint();
}
}
可以通過將applet的停止和運行方法替換為:
private volatile Thread blinker;
public void stop() {
blinker = null;
}
public void run() {
Thread thisThread = Thread.currentThread();
while (blinker == thisThread) {
try {
Thread.sleep(interval);
} catch (InterruptedException e){
}
repaint();
}
}
如何停止等待很長時間的線程(例如,等待輸入)?
這就是線程.中斷方法的作用所在??梢允褂孟嗤摹盎跔顟B”的信令機制,但狀態更改(在前面的示例中,閃爍值=NULL)之后可以調用Thread.中斷,以中斷等待:
public void stop() {
Thread moribund = waiter;
waiter = null;
moribund.interrupt();
}
要使此技術有效,任何捕獲中斷異常且不準備立即處理該異常的方法都必須重新聲明異常。我們說的是重拋而不是重新拋出,因為重新拋出異常并不總是可能的。如果未聲明捕獲InterruptedException的方法拋出此(已檢查)異常,則應使用以下咒語“重新中斷自身”:
Thread.currentThread().interrupt();
這將確保線程一旦能夠恢復InterruptedException。
如果線程沒有響應線程。中斷怎么辦?
在某些情況下,您可以使用特定于應用程序的技巧。例如,如果線程正在等待已知的套接字,則可以關閉套接字以使線程立即返回。不幸的是,實際上沒有任何技術在一般情況下起作用。應該注意的是,在所有等待線程不響應Thread.中斷的情況下,它也不會響應Thread.Stop。這種情況包括蓄意拒絕服務攻擊,以及I/O操作,這些操作的線程.停止和線程.中斷不能正常工作。
為什么線程暫停和線程恢復不再受歡迎?
線程。掛起天生容易死鎖。如果目標線程在監視器上持有一個鎖,在關鍵系統資源掛起時保護該資源,則在目標線程恢復之前,任何線程都不能訪問該資源。如果要恢復目標線程的線程在調用resume之前嘗試鎖定此監視器,則會導致死鎖。這種死鎖通常表現為“凍結”進程。
我應該用什么來代替線程暫停和線程恢復?
與Thread.top一樣,謹慎的方法是讓“目標線程”輪詢一個變量,該變量指示線程的所需狀態(活動或掛起)。當所需的狀態被掛起時,線程將使用Object.Wait等待。
當線程被恢復時,目標線程將被使用Object.Notification通知。例如,假設您的applet包含以下mousePress事件處理程序,該處理程序將切換名為閃爍器的線程的狀態:
private boolean threadSuspended;
Public void mousePressed(MouseEvent e) {
e.consume();
if (threadSuspended)
blinker.resume();
else
blinker.suspend(); // DEADLOCK-PRONE!
threadSuspended = !threadSuspended;
}
可以通過將上面的事件處理程序替換為:
public synchronized void mousePressed(MouseEvent e) {
e.consume();
threadSuspended = !threadSuspended;
if (!threadSuspended)
notify();
}
并將以下代碼添加到“Run循環”中:
synchronized(this) {
while (threadSuspended)
wait();
}
等待方法拋出InterruptedException,因此它必須在一次嘗試中.捕獲條款。把它和睡眠放在同一個條款里是可以的。檢查應該跟隨(而不是在睡眠之前),因此當線程“恢復”時,立即重新繪制窗口。得到的Run方法如下:
public void run() {
while (true) {
try {
Thread.sleep(interval);
synchronized(this) {
while (threadSuspended)
wait();
}
} catch (InterruptedException e){
}
repaint();
}
}
注意,mousePress方法中的Notification和Run方法中的Wait都在同步塊中。這是語言所要求的,并確保等待和通知被正確序列化。實際上,這消除了可能導致“掛起”線程丟失通知并無限期掛起的爭用條件。
雖然Java中的同步成本隨著平臺的成熟而降低,但它永遠不會是免費的??梢允褂靡粋€簡單的技巧來刪除我們添加到“Run循環”每次迭代中的同步。添加的同步塊被稍微復雜一些的代碼替換,只有在線程實際掛起時才進入同步塊:
if (threadSuspended) {
synchronized(this) {
while (threadSuspended)
wait();
}
}
在沒有顯式同步的情況下,必須使線程懸掛不穩定,以確保暫停請求的及時通信。結果的Run方法是:
private volatile boolean threadSuspended;
public void run() {
while (true) {
try {
Thread.sleep(interval);
if (threadSuspended) {
synchronized(this) {
while (threadSuspended)
wait();
}
}
} catch (InterruptedException e){
}
repaint();
}
}
能否將這兩種技術結合起來,生成一個可以安全“停止”或“掛起”的線程?
是的,很簡單。其中一個微妙之處是,當另一個線程試圖停止目標線程時,該線程可能已經掛起。如果stop方法只是將狀態變量(blinker)設置為null,那么目標線程將保持掛起狀態(在監視器上等待),而不是正常退出。如果重新啟動小程序,多個線程可能會同時等待監視器,從而導致不穩定的行為。
要糾正這種情況,stop方法必須確保目標線程在掛起時立即恢復。一旦目標線程恢復,它必須立即意識到它已經停止,并優雅地退出。下面是生成的run和stop方法的外觀:
public void run() {
Thread thisThread = Thread.currentThread();
while (blinker == thisThread) {
try {
Thread.sleep(interval);
synchronized(this) {
while (threadSuspended && blinker==thisThread)
wait();
}
} catch (InterruptedException e){
}
repaint();
}
}
public synchronized void stop() {
blinker = null;
notify();
}
如上文所述,如果停止方法調用Thread.中斷,它也不必調用Notification,但它仍然必須是同步的。這可以確保目標線程不會因為爭用條件而錯過中斷。
那如何線程銷毀?
線程破壞性從來沒有實現過,并且已經被廢棄了。如果實現了它,就會以線程銷毀的方式出現死鎖。(實際上,它大致相當于Thread.休會,而不可能出現后續的Thread.Response)。
為什么是運行時.runFinalizersOnExit不贊成?
因為它本質上是不安全的。它可能導致在活動對象上調用終結器,而其他線程則同時操作這些對象,從而導致異常行為或死鎖。雖然這個問題是可以避免的,如果其對象正在最后確定的類被編碼為“防御”這個調用,大多數程序員不抵抗它。它們假設對象在調用終結器時已經死亡。此外,調用并不是“線程安全”,因為它設置了VM全局標志。這迫使每個類使用終結器來防御活動對象的終結!
總結
以上是生活随笔為你收集整理的java mousepress_Java线程原语弃用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梅州备案价查询(梅州备案)
- 下一篇: 安卓导航(汽车导航安卓)