如何實現一個安全的thread.stop的api?
01-01
由於資源的佔用,共享數據的不一致,強制停止一個thread時候可能導致安全問題。Java不建議使用thread.stop這樣的api (https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html),(java - Thread.stop()),而是建議使用interrupt這樣的介面來向目標線程發送消息,由目標線程來完成停止的工作。
Java里一個線程調用了Thread.interrupt()到底意味著什麼? - Java 虛擬機(JVM)問題如下:
1. 目前已有的語言或研究中,有沒有支持安全停止線程的實踐?2. 有無可能設計並實現一個安全的thread.stop?3. 如果有,需要考慮哪些問題,如何克服?
Impossible. 線程只能自殺,不能被殺,否則程序狀態不可控。例如線程正持有鎖,數據更新了一半,被殺,鎖誰來釋放?就算別的線程可以釋放鎖,那數據狀態不一致怎麼修復?就拿最簡單的 LinkedList 來說,如果某個線程在調用 add() 的時候被殺,add() 剛好執行了一半,鏈表結構被破壞。那其他線程怎麼判斷這個 LinkedList 的內部狀態是否一致?就算有辦法做到,也是 O(N) 級別的耗時操作,那其他線程選擇什麼時機去執行這一耗時的判斷?
參考C#的CancellationToken
另外,C#設計了一些不可被打斷的代碼位置,其中就包含finally塊,這樣就可以避免上面所說的釋放鎖的問題,因為釋放鎖一般都是放在finally塊裡面的。當程序執行到finally塊時,Abort不能立即終結線程,必須等到finally塊執行完成。
同樣的,Thread.Abort會在目標線程引發異常,從而確保代碼在try塊中執行的時候,對應的finally塊會被執行,這樣又避開了上面所說的造成數據不一致的問題。
你把線程問題看成分散式數據一致性問題來看,只是時間超時是0,數據可以內存共享。然後再看陳碩說的,被外部殺了,相當於線程的時間超時不是0了,真的超時了,就知道只有一份數據是很難保證數據的準確了。
一般認為線程是不應該可以被cancel,但stop還是可以有的,stop之後還可以resume嘛。而且不僅可以stop,在一些關鍵場合還應該允許一些運行故障,比如某個cpu掛掉之類的問題。主要存在的問題,其他人都有提及。解決的辦法就是使用不會鎖死的演算法(lock-free或者wait-free)實現,以及構建於這些演算法之上的系統。
java中只能靠thread的interrupt並結合線程內任務的邏輯來控制線程的stop。
所以要實現一個可以被停止的線程任務,必須檢查interrupt相關的異常並且在任務執行中每個階段檢察一下interrupted狀態來實現完整的退出。
不得不再吐槽下,現在有個項目組在某個組件中大量使用了線程來實現多任務,但是每個任務的退出都沒有被正確實現導致了額外的資源被佔用。如果有更優雅的退出方式我們就不用替他們擦這個屁股了!推薦閱讀: