詳解Java多線程編程中線程的啟動、中止或終止操作。本站提示廣大學習愛好者:(詳解Java多線程編程中線程的啟動、中止或終止操作)文章只能為提供參考,不一定能成為您想要的結果。以下是詳解Java多線程編程中線程的啟動、中止或終止操作正文
線程啟動:
1.start() 和 run()的差別解釋
start() : 它的感化是啟動一個新線程,新線程會履行響應的run()辦法。start()不克不及被反復挪用。
run() : run()就和通俗的成員辦法一樣,可以被反復挪用。零丁挪用run()的話,會在以後線程中履行run(),而其實不會啟動新線程!
上面以代碼來停止解釋。
class MyThread extends Thread{ public void run(){ ... } }; MyThread mythread = new MyThread();
mythread.start()會啟動一個新線程,並在新線程中運轉run()辦法。
而mythread.run()則會直接在以後線程中運轉run()辦法,其實不會啟動一個新線程來運轉run()。
2.start() 和 run()的差別示例
上面,經由過程一個簡略示例演示它們之間的差別。源碼以下:
// Demo.java 的源碼 class MyThread extends Thread{ public MyThread(String name) { super(name); } public void run(){ System.out.println(Thread.currentThread().getName()+" is running"); } }; public class Demo { public static void main(String[] args) { Thread mythread=new MyThread("mythread"); System.out.println(Thread.currentThread().getName()+" call mythread.run()"); mythread.run(); System.out.println(Thread.currentThread().getName()+" call mythread.start()"); mythread.start(); } }
運轉成果:
main call mythread.run() main is running main call mythread.start() mythread is running
成果解釋:
(1) Thread.currentThread().getName()是用於獲得“以後線程”的名字。以後線程是斧正在cpu中調劑履行的線程。
(2) mythread.run()是在“主線程main”中挪用的,該run()辦法直接運轉在“主線程main”上。
(3) mythread.start()會啟動“線程mythread”,“線程mythread”啟動以後,會挪用run()辦法;此時的run()辦法是運轉在“線程mythread”上。
線程的中止和終止
1、線程中止:interrupt()
interrupt()的感化是中止本線程。
本線程中止本身是被許可的;其它線程挪用本線程的interrupt()辦法時,會經由過程checkAccess()檢討權限。這有能夠拋出SecurityException異常。
假如本線程是處於壅塞狀況:挪用線程的wait(), wait(long)或wait(long, int)會讓它進入期待(壅塞)狀況,或許挪用線程的join(), join(long), join(long, int), sleep(long), sleep(long, int)也會讓它進入壅塞狀況。若線程在壅塞狀況時,挪用了它的interrupt()辦法,那末它的“中止狀況”會被消除而且會收到一個InterruptedException異常。例如,線程經由過程wait()進入壅塞狀況,此時經由過程interrupt()中止該線程;挪用interrupt()會立刻將線程的中止標志設為“true”,然則因為線程處於壅塞狀況,所以該“中止標志”會立刻被消除為“false”,同時,會發生一個InterruptedException的異常。
假如線程被壅塞在一個Selector選擇器中,那末經由過程interrupt()中止它時;線程的中止標志會被設置為true,而且它會立刻從選擇操作中前往。
假如不屬於後面所說的情形,那末經由過程interrupt()中止線程時,它的中止標志會被設置為“true”。
中止一個“已終止的線程”不會發生任何操作。
2、線程終止
Thread中的stop()和suspend()辦法,因為固有的不平安性,曾經建議不再應用!
上面,我先分離評論辯論線程在“壅塞狀況”和“運轉狀況”的終止方法,然後再總結出一個通用的方法。
1. 終止處於“壅塞狀況”的線程
平日,我們經由過程“中止”方法終止處於“壅塞狀況”的線程。
當線程因為被挪用了sleep(), wait(), join()等辦法而進入壅塞狀況;若此時挪用線程的interrupt()將線程的中止標志設為true。因為處於壅塞狀況,中止標志會被消除,同時發生一個InterruptedException異常。將InterruptedException放在恰當的為止就可以終止線程,情勢以下:
@Override public void run() { try { while (true) { // 履行義務... } } catch (InterruptedException ie) { // 因為發生InterruptedException異常,加入while(true)輪回,線程終止! } }
解釋:在while(true)中赓續的履行義務,當線程處於壅塞狀況時,挪用線程的interrupt()發生InterruptedException中止。中止的捕捉在while(true)以外,如許就加入了while(true)輪回!
留意:對InterruptedException的捕捉務普通放在while(true)輪回體的裡面,如許,在發生異常時就加入了while(true)輪回。不然,InterruptedException在while(true)輪回體以內,就須要額定的添加加入處置。情勢以下:
@Override public void run() { while (true) { try { // 履行義務... } catch (InterruptedException ie) { // InterruptedException在while(true)輪回體內。 // 當線程發生了InterruptedException異常時,while(true)仍能持續運轉!須要手動加入 break; } } }
解釋:下面的InterruptedException異常的捕捉在whle(true)以內。當發生InterruptedException異常時,被catch處置以外,依然在while(true)輪回體內;要加入while(true)輪回體,須要額定的履行加入while(true)的操作。
2. 終止處於“運轉狀況”的線程
平日,我們經由過程“標志”方法終止處於“運轉狀況”的線程。個中,包含“中止標志”和“額定添加標志”。
(1) 經由過程“中止標志”終止線程。
情勢以下:
@Override public void run() { while (!isInterrupted()) { // 履行義務... } }
解釋:isInterrupted()是斷定線程的中止標志是否是為true。當線程處於運轉狀況,而且我們須要終止它時;可以挪用線程的interrupt()辦法,應用線程的中止標志為true,即isInterrupted()會前往true。此時,就會加入while輪回。
留意:interrupt()其實不會終止處於“運轉狀況”的線程!它會將線程的中止標志設為true。
(2) 經由過程“額定添加標志”。
情勢以下:
private volatile boolean flag= true; protected void stopTask() { flag = false; } @Override public void run() { while (flag) { // 履行義務... } }
解釋:線程中有一個flag標志,它的默許值是true;而且我們供給stopTask()來設置flag標志。當我們須要終止該線程時,挪用該線程的stopTask()辦法便可以讓線程加入while輪回。
留意:將flag界說為volatile類型,是為了包管flag的可見性。即其它線程經由過程stopTask()修正了flag以後,本線程能看到修正後的flag的值。
綜合線程處於“壅塞狀況”和“運轉狀況”的終止方法,比擬通用的終止線程的情勢以下:
@Override public void run() { try { // 1. isInterrupted()包管,只需中止標志為true就終止線程。 while (!isInterrupted()) { // 履行義務... } } catch (InterruptedException ie) { // 2. InterruptedException異常包管,當InterruptedException異常發生時,線程被終止。 } }
3. 終止線程的示例
interrupt()經常被用來終止“壅塞狀況”線程。參考上面示例:
// Demo1.java的源碼 class MyThread extends Thread { public MyThread(String name) { super(name); } @Override public void run() { try { int i=0; while (!isInterrupted()) { Thread.sleep(100); // 休眠100ms i++; System.out.println(Thread.currentThread().getName()+" ("+this.getState()+") loop " + i); } } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName() +" ("+this.getState()+") catch InterruptedException."); } } } public class Demo1 { public static void main(String[] args) { try { Thread t1 = new MyThread("t1"); // 新建“線程t1” System.out.println(t1.getName() +" ("+t1.getState()+") is new."); t1.start(); // 啟動“線程t1” System.out.println(t1.getName() +" ("+t1.getState()+") is started."); // 主線程休眠300ms,然後主線程給t1發“中止”指令。 Thread.sleep(300); t1.interrupt(); System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted."); // 主線程休眠300ms,然後檢查t1的狀況。 Thread.sleep(300); System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now."); } catch (InterruptedException e) { e.printStackTrace(); } } }
運轉成果:
t1 (NEW) is new. t1 (RUNNABLE) is started. t1 (RUNNABLE) loop 1 t1 (RUNNABLE) loop 2 t1 (TIMED_WAITING) is interrupted. t1 (RUNNABLE) catch InterruptedException. t1 (TERMINATED) is interrupted now.
成果解釋:
(1) 主線程main中經由過程new MyThread("t1")創立線程t1,以後經由過程t1.start()啟動線程t1。
(2) t1啟動以後,會赓續的檢討它的中止標志,假如中止標志為“false”;則休眠100ms。
(3) t1休眠以後,會切換到主線程main;主線程再次運轉時,會履行t1.interrupt()中止線程t1。t1收到中止指令以後,會將t1的中止標志設置“false”,並且會拋出InterruptedException異常。在t1的run()辦法中,是在輪回體while以外捕捉的異常;是以輪回被終止。
我們對下面的成果停止小小的修正,將run()辦法中捕捉InterruptedException異常的代碼塊移到while輪回體內。
// Demo2.java的源碼 class MyThread extends Thread { public MyThread(String name) { super(name); } @Override public void run() { int i=0; while (!isInterrupted()) { try { Thread.sleep(100); // 休眠100ms } catch (InterruptedException ie) { System.out.println(Thread.currentThread().getName() +" ("+this.getState()+") catch InterruptedException."); } i++; System.out.println(Thread.currentThread().getName()+" ("+this.getState()+") loop " + i); } } } public class Demo2 { public static void main(String[] args) { try { Thread t1 = new MyThread("t1"); // 新建“線程t1” System.out.println(t1.getName() +" ("+t1.getState()+") is new."); t1.start(); // 啟動“線程t1” System.out.println(t1.getName() +" ("+t1.getState()+") is started."); // 主線程休眠300ms,然後主線程給t1發“中止”指令。 Thread.sleep(300); t1.interrupt(); System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted."); // 主線程休眠300ms,然後檢查t1的狀況。 Thread.sleep(300); System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now."); } catch (InterruptedException e) { e.printStackTrace(); } } }
運轉成果:
t1 (NEW) is new. t1 (RUNNABLE) is started. t1 (RUNNABLE) loop 1 t1 (RUNNABLE) loop 2 t1 (TIMED_WAITING) is interrupted. t1 (RUNNABLE) catch InterruptedException. t1 (RUNNABLE) loop 3 t1 (RUNNABLE) loop 4 t1 (RUNNABLE) loop 5 t1 (TIMED_WAITING) is interrupted now. t1 (RUNNABLE) loop 6 t1 (RUNNABLE) loop 7 t1 (RUNNABLE) loop 8 t1 (RUNNABLE) loop 9 ...
成果解釋:
法式進入了逝世輪回!
為何會如許呢?這是由於,t1在“期待(壅塞)狀況”時,被interrupt()中止;此時,會消除中止標志[即isInterrupted()會前往false],並且會拋出InterruptedException異常[該異常在while輪回體內被捕捉]。是以,t1天經地義的會進入逝世輪回了。
處理該成績,須要我們在捕捉異常時,額定的停止加入while輪回的處置。例如,在MyThread的catch(InterruptedException)中添加break 或 return就可以處理該成績。
上面是經由過程“額定添加標志”的方法終止“狀況狀況”的線程的示例:
// Demo3.java的源碼 class MyThread extends Thread { private volatile boolean flag= true; public void stopTask() { flag = false; } public MyThread(String name) { super(name); } @Override public void run() { synchronized(this) { try { int i=0; while (flag) { Thread.sleep(100); // 休眠100ms i++; System.out.println(Thread.currentThread().getName()+" ("+this.getState()+") loop " + i); } } catch (InterruptedException ie) { System.out.println(Thread.currentThread().getName() +" ("+this.getState()+") catch InterruptedException."); } } } } public class Demo3 { public static void main(String[] args) { try { MyThread t1 = new MyThread("t1"); // 新建“線程t1” System.out.println(t1.getName() +" ("+t1.getState()+") is new."); t1.start(); // 啟動“線程t1” System.out.println(t1.getName() +" ("+t1.getState()+") is started."); // 主線程休眠300ms,然後主線程給t1發“中止”指令。 Thread.sleep(300); t1.stopTask(); System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted."); // 主線程休眠300ms,然後檢查t1的狀況。 Thread.sleep(300); System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now."); } catch (InterruptedException e) { e.printStackTrace(); } } }
運轉成果:
t1 (NEW) is new. t1 (RUNNABLE) is started. t1 (RUNNABLE) loop 1 t1 (RUNNABLE) loop 2 t1 (TIMED_WAITING) is interrupted. t1 (RUNNABLE) loop 3 t1 (TERMINATED) is interrupted now.