摘要:一線程的基本概念單線程簡單的說,單線程就是進程中只有一個線程。多線程由一個以上線程組成的程序稱為多線程程序。當線程調用完方法進入后會自動釋放鎖,線程獲得鎖。
一、線程的基本概念 1.1 單線程
簡單的說,單線程就是進程中只有一個線程。單線程在程序執行時,所走的程序路徑按照連續順序排下來,前面的必須處理好,后面的才會執行。
Java示例:
public class SingleThread { public static void main(String[] args) { for (int i = 0; i < 10000; i++) { System.out.print(i + " "); } } }
上述Java代碼中,只有一個主線程執行main方法。
1.2 多線程由一個以上線程組成的程序稱為多線程程序。常見的多線程程序如:GUI應用程序、I/O操作、網絡容器等。
Java中,一定是從主線程開始執行(main方法),然后在主線程的某個位置啟動新的線程。
Java中創建多線程類兩種方法:
1、繼承java.lang.Thread
Java示例:
public class MyThread extends Thread { public void run() { for (int i = 0; i < 10000; i++) { System.out.print(i + " "); } } } public class MultiThread { public static void main(String[] args) { MyThread t = new MyThread(); t.start(); //啟動子線程 //主線程繼續同時向下執行 for (int i = 0; i < 10000; i++) { System.out.print(i + " "); } } }
上述代碼中,MyThread類繼承了類java.lang.Thread,并覆寫了run方法。主線程從main方法開始執行,當主線程執行至t.start()時,啟動新線程(注意此處是調用start方法,不是run方法),新線程會并發執行自身的run方法。
2、實現java.lang.Runnable接口
Java示例:
public class MyThread implements Runnable { public void run() { for (int i = 0; i < 10000; i++) { System.out.print(i + " "); } } } public class MultiThread { public static void main(String[] args) { Thread t = new Thread(new MyThread()); t.start(); //啟動子線程 //主線程繼續同時向下執行 for (int i = 0; i < 10000; i++) { System.out.print(i + " "); } } }
上述代碼中,MyThread類實現了java.lang.Runnable接口,并覆寫了run方法,其它與繼承java.lang.Thread完全相同。實際上,java.lang.Thread類本身也實現了Runnable接口,只不過java.lang.Thread類的run方法主體里空的,通常被子類覆寫(override)。
注意:主線程執行完成后,如果還有子線程正在執行,程序也不會結束。只有當所有線程都結束時(不含Daemon Thread),程序才會結束。2.2 暫停
Java中線程的暫停是調用java.lang.Thread類的sleep方法(注意是類方法)。該方法會使當前正在執行的線程暫停指定的時間,如果線程持有鎖,sleep方法結束前并不會釋放該鎖。
Java示例:
public class Main { public static void main(String[] args) { for (int i = 0; i < 10; i++) { System.out.print(i + " "); try { Thread.sleep(1000); //當前main線程暫停1000ms } catch (InterruptedException e) { } } } }
上述代碼中,當main線程調用Thread.sleep(1000)后,線程會被暫停,如果被interrupt,則會拋出InterruptedException異常。
2.3 互斥Java中線程的共享互斥操作,會使用synchronized關鍵字。線程共享互斥的架構稱為監視(monitor),而獲取鎖有時也稱為“持有(own)監視”。
每個鎖在同一時刻,只能由一個線程持有。
注意:synchronized方法或聲明執行期間,如程序遇到任何異常或return,線程都會釋放鎖。
1、synchronized方法
Java示例1:
//synchronized實例方法 public synchronized void deposit(int m) { System.out.print("This is synchronized method."); }
注:synchronized實例方法采用this鎖(即當前對象)去做線程的共享互斥。
Java示例2:
//synchronized類方法 public static synchronized void deposit(int m) { System.out.print("This is synchronized static method."); }
注:synchronized類方法采用類對象鎖(即當前類的類對象)去做線程的共享互斥。如上述示例中,采用類.class(繼承自java.lang.Class)作為鎖。
2、synchronized聲明
Java示例:
public void deposit(int m) { synchronized (this) { System.out.print("This is synchronized statement with this lock."); } synchronized (Something.class) { System.out.print("This is synchronized statement with class lock."); } }
注:synchronized聲明可以采用任意鎖,上述示例中,分別采用了對象鎖(this)和類鎖(something.class)
2.4 中斷java.lang.Thread類有一個interrupt方法,該方法直接對線程調用。當被interrupt的線程正在sleep或wait時,會拋出InterruptedException異常。
事實上,interrupt方法只是改變目標線程的中斷狀態(interrupt status),而那些會拋出InterruptedException異常的方法,如wait、sleep、join等,都是在方法內部不斷地檢查中斷狀態的值。
interrupt方法
Thread實例方法:必須由其它線程獲取被調用線程的實例后,進行調用。實際上,只是改變了被調用線程的內部中斷狀態;
Thread.interrupted方法
Thread類方法:必須在當前執行線程內調用,該方法返回當前線程的內部中斷狀態,然后清除中斷狀態(置為false) ;
isInterrupted方法
Thread實例方法:用來檢查指定線程的中斷狀態。當線程為中斷狀態時,會返回true;否則返回false。
2.5 協調1、wait set / wait方法
wait set是一個虛擬的概念,每個Java類的實例都有一個wait set,當對象執行wait方法時,當前線程就會暫停,并進入該對象的wait set。
當發生以下事件時,線程才會退出wait set:
①有其它線程以notify方法喚醒該線程
②有其它線程以notifyAll方法喚醒該線程
③有其它線程以interrupt方法喚醒該線程
④wait方法已到期
注:當前線程若要執行obj.wait(),則必須先獲取該對象鎖。當線程進入wait set后,就已經釋放了該對象鎖。
下圖中線程A先獲得對象鎖,然后調用wait()方法(此時線程B無法獲取鎖,只能等待)。當線程A調用完wait()方法進入wait set后會自動釋放鎖,線程B獲得鎖。
2、notify方法
notify方法相當于從wait set中從挑出一個線程并喚醒。
下圖中線程A在當前實例對象的wait set中等待,此時線程B必須拿到同一實例的對象鎖,才能調用notify方法喚醒wait set中的任意一個線程。
注:線程B調用notify方法后,并不會立即釋放鎖,會有一段時間差。
3、notifyAll方法
notifyAll方法相當于將wait set中的所有線程都喚醒。
4、總結
wait、notify、notifyAll這三個方法都是java.lang.Object類的方法(注意,不是Thread類的方法)。
若線程沒有拿到當前對象鎖就直接調用對象的這些方法,都會拋出java.lang.IllegalMonitorStateException異常。
obj.wait()是把當前線程放到obj的wait set;
obj.notify()是從obj的wait set里喚醒1個線程;
obj.notifyAll()是喚醒所有在obj的wait set里的線程。
三、線程的狀態轉移當創建一個Thread子類或實現Runnable接口類的實例時,線程進入【初始】狀態;
調用實例的start方法后,線程進入【可執行】狀態;
系統會在某一時刻自動調度處于【可執行】狀態的線程,被調度的線程會調用run方法,進入【執行中】狀態;
線程執行完run方法后,進入【結束】狀態;
處于【結束】狀態的線程,在某一時刻,會被JVM垃圾回收;
處于【執行中】狀態的線程,若調用了Thread.yield方法,會回到【可執行】狀態,等待再次被調度;
處于【執行中】狀態的線程,若調用了wait方法,會進入wait set并一直等待,直到被其它線程通過notify、notifyAll、interrupt方法喚醒;
處于【執行中】狀態的線程,若調用了Thread.sleep方法,會進入【Sleep】狀態,無法繼續向下執行。當sleep時間結束或被interrupt時,會回到【可執行狀態】;
處于【執行中】狀態的線程,若遇到阻塞I/O操作,也會停止等待I/O完成,然后回到【可執行狀態】;
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/71491.html
摘要:前言想要進入等一線互聯網公司,以下是你必需具備的技能。包由解釋程序自動加載,不需要顯示說明。包包括許多具有特定功能的類,有日期向量哈希表堆棧等,其中類支持與時間有關的操作。包定義了應用程序編程接口,是應用程序環境的中性平臺組件結構。 前言 想要進入BAT等一線互聯網公司,以下是你必需具備的技能。如果你掌握的不牢固,那就趕快鞏固,如果你還沒有涉及,現在就立馬學習起來吧。 1.Java語言...
閱讀 1257·2023-04-25 18:57
閱讀 2144·2023-04-25 16:28
閱讀 3948·2021-11-24 09:39
閱讀 3644·2021-11-16 11:45
閱讀 1834·2021-10-13 09:40
閱讀 1273·2019-08-30 15:52
閱讀 1727·2019-08-30 10:57
閱讀 672·2019-08-29 16:55