JAVA線程終止方式的思考,java線程終止
在java的線程中提供了stop這個方法來終止線程的執行,但是使用這種方式來終止線程的執行時非常危險的,這樣子會破壞線程執行的原子性,導致資料丟失或者其他什麼更為嚴重的問題。所以,在java的規範中不建議使用這種方法來終止線程的執行。那麼,既然這種方法是不建議使用的,而我們在實際的項目開發過程中是需要對線程進行中斷的,那我們該怎麼辦呢?
解決的方式就是採用一個標誌位的方法來控制,線程輪詢這個標誌位,當發現這個標誌位發生改變的時候,線程進行終止,這樣比較安全一些。代碼如下:
package thread;import java.util.concurrent.TimeUnit;public class StopThread { private static boolean stop = false; public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Runnable() { @Override public void run() { int i = 0; while (stop == false) { System.out.print(i + "\t"); i++; } } }); thread.start(); TimeUnit.SECONDS.sleep(1); stop = true; }}
但這種方式在有的情況下會一直執行下去,並不會像我們所預期的那樣正常的終止線程的執行,問題在於,沒有使用同步,就不能保證背景線程什麼時候看到標誌位所做的改變。
要解決這個問題,我們只能寫一個同步的方法,輪詢這個標誌位,代碼如下:
package thread;import java.util.concurrent.TimeUnit;public class StopThread2 implements Runnable{ private boolean is = false; private int i = 0; public synchronized boolean isStop(){ return is; } public synchronized void setIs(boolean is){ this.is = is; } @Override public void run() { while(!isStop()){ System.out.println(i); i++; } } public static void main(String[] args) throws InterruptedException { StopThread2 th2 = new StopThread2(); Thread thread = new Thread(th2); thread.start(); //線程啟動 TimeUnit.SECONDS.sleep(1); th2.setIs(true); }}
在isStop()方法中的操作,即使沒有同步,也是原子性的,這些方法只是為了他們的通訊效果,並不是為了變數的互斥訪問。雖然迴圈迭代的開銷很小,但是我們還有一種更為簡潔和更為高效的方法,那就是使用volatile來修飾。
我們都知道,編譯器為了使我們的代碼執行的效率更高,對於變數,它使用了一種緩衝機制。在多線程中,變數被多個線程訪問的時候,被修改的值常常來不及放入到緩衝中,就被其他的線程所訪問,這容易造成不一致的問題,使用volatile就可以很好的來解決這個問題。使用volatile修飾的變數是不進行緩衝的,使得線程可以迅速的看到其他線程對這個值所作出的修改。結合我們現在的情境進行分析,我們發現,我們在這裡可以使用這個關鍵字對我們的代碼進行最佳化處理。修改後的代碼如下:
package thread;import java.util.concurrent.TimeUnit;public class StopThread2 implements Runnable{ private volatile boolean is = false; private int i = 0; @Override public void run() { while(!is){ System.out.println(i); i++; } } public static void main(String[] args) throws InterruptedException { StopThread2 th2 = new StopThread2(); Thread thread = new Thread(th2); thread.start(); //線程啟動 TimeUnit.SECONDS.sleep(1); th2.is = true; }}