摘要:一線程的基本概念單線程簡單的說,單線程就是進(jìn)程中只有一個(gè)線程。多線程由一個(gè)以上線程組成的程序稱為多線程程序。當(dāng)線程調(diào)用完方法進(jìn)入后會(huì)自動(dòng)釋放鎖,線程獲得鎖。
一、線程的基本概念 1.1 單線程
簡單的說,單線程就是進(jìn)程中只有一個(gè)線程。單線程在程序執(zhí)行時(shí),所走的程序路徑按照連續(xù)順序排下來,前面的必須處理好,后面的才會(huì)執(zhí)行。
Java示例:
public class SingleThread { public static void main(String[] args) { for (int i = 0; i < 10000; i++) { System.out.print(i + " "); } } }
上述Java代碼中,只有一個(gè)主線程執(zhí)行main方法。
1.2 多線程由一個(gè)以上線程組成的程序稱為多線程程序。常見的多線程程序如:GUI應(yīng)用程序、I/O操作、網(wǎng)絡(luò)容器等。
Java中,一定是從主線程開始執(zhí)行(main方法),然后在主線程的某個(gè)位置啟動(dòng)新的線程。
Java中創(chuàng)建多線程類兩種方法:
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(); //啟動(dòng)子線程 //主線程繼續(xù)同時(shí)向下執(zhí)行 for (int i = 0; i < 10000; i++) { System.out.print(i + " "); } } }
上述代碼中,MyThread類繼承了類java.lang.Thread,并覆寫了run方法。主線程從main方法開始執(zhí)行,當(dāng)主線程執(zhí)行至t.start()時(shí),啟動(dòng)新線程(注意此處是調(diào)用start方法,不是run方法),新線程會(huì)并發(fā)執(zhí)行自身的run方法。
2、實(shí)現(xiàn)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(); //啟動(dòng)子線程 //主線程繼續(xù)同時(shí)向下執(zhí)行 for (int i = 0; i < 10000; i++) { System.out.print(i + " "); } } }
上述代碼中,MyThread類實(shí)現(xiàn)了java.lang.Runnable接口,并覆寫了run方法,其它與繼承java.lang.Thread完全相同。實(shí)際上,java.lang.Thread類本身也實(shí)現(xiàn)了Runnable接口,只不過java.lang.Thread類的run方法主體里空的,通常被子類覆寫(override)。
注意:主線程執(zhí)行完成后,如果還有子線程正在執(zhí)行,程序也不會(huì)結(jié)束。只有當(dāng)所有線程都結(jié)束時(shí)(不含Daemon Thread),程序才會(huì)結(jié)束。2.2 暫停
Java中線程的暫停是調(diào)用java.lang.Thread類的sleep方法(注意是類方法)。該方法會(huì)使當(dāng)前正在執(zhí)行的線程暫停指定的時(shí)間,如果線程持有鎖,sleep方法結(jié)束前并不會(huì)釋放該鎖。
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); //當(dāng)前main線程暫停1000ms } catch (InterruptedException e) { } } } }
上述代碼中,當(dāng)main線程調(diào)用Thread.sleep(1000)后,線程會(huì)被暫停,如果被interrupt,則會(huì)拋出InterruptedException異常。
2.3 互斥Java中線程的共享互斥操作,會(huì)使用synchronized關(guān)鍵字。線程共享互斥的架構(gòu)稱為監(jiān)視(monitor),而獲取鎖有時(shí)也稱為“持有(own)監(jiān)視”。
每個(gè)鎖在同一時(shí)刻,只能由一個(gè)線程持有。
注意:synchronized方法或聲明執(zhí)行期間,如程序遇到任何異?;騬eturn,線程都會(huì)釋放鎖。
1、synchronized方法
Java示例1:
//synchronized實(shí)例方法 public synchronized void deposit(int m) { System.out.print("This is synchronized method."); }
注:synchronized實(shí)例方法采用this鎖(即當(dāng)前對(duì)象)去做線程的共享互斥。
Java示例2:
//synchronized類方法 public static synchronized void deposit(int m) { System.out.print("This is synchronized static method."); }
注:synchronized類方法采用類對(duì)象鎖(即當(dāng)前類的類對(duì)象)去做線程的共享互斥。如上述示例中,采用類.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聲明可以采用任意鎖,上述示例中,分別采用了對(duì)象鎖(this)和類鎖(something.class)
2.4 中斷java.lang.Thread類有一個(gè)interrupt方法,該方法直接對(duì)線程調(diào)用。當(dāng)被interrupt的線程正在sleep或wait時(shí),會(huì)拋出InterruptedException異常。
事實(shí)上,interrupt方法只是改變目標(biāo)線程的中斷狀態(tài)(interrupt status),而那些會(huì)拋出InterruptedException異常的方法,如wait、sleep、join等,都是在方法內(nèi)部不斷地檢查中斷狀態(tài)的值。
interrupt方法
Thread實(shí)例方法:必須由其它線程獲取被調(diào)用線程的實(shí)例后,進(jìn)行調(diào)用。實(shí)際上,只是改變了被調(diào)用線程的內(nèi)部中斷狀態(tài);
Thread.interrupted方法
Thread類方法:必須在當(dāng)前執(zhí)行線程內(nèi)調(diào)用,該方法返回當(dāng)前線程的內(nèi)部中斷狀態(tài),然后清除中斷狀態(tài)(置為false) ;
isInterrupted方法
Thread實(shí)例方法:用來檢查指定線程的中斷狀態(tài)。當(dāng)線程為中斷狀態(tài)時(shí),會(huì)返回true;否則返回false。
2.5 協(xié)調(diào)1、wait set / wait方法
wait set是一個(gè)虛擬的概念,每個(gè)Java類的實(shí)例都有一個(gè)wait set,當(dāng)對(duì)象執(zhí)行wait方法時(shí),當(dāng)前線程就會(huì)暫停,并進(jìn)入該對(duì)象的wait set。
當(dāng)發(fā)生以下事件時(shí),線程才會(huì)退出wait set:
①有其它線程以notify方法喚醒該線程
②有其它線程以notifyAll方法喚醒該線程
③有其它線程以interrupt方法喚醒該線程
④wait方法已到期
注:當(dāng)前線程若要執(zhí)行obj.wait(),則必須先獲取該對(duì)象鎖。當(dāng)線程進(jìn)入wait set后,就已經(jīng)釋放了該對(duì)象鎖。
下圖中線程A先獲得對(duì)象鎖,然后調(diào)用wait()方法(此時(shí)線程B無法獲取鎖,只能等待)。當(dāng)線程A調(diào)用完wait()方法進(jìn)入wait set后會(huì)自動(dòng)釋放鎖,線程B獲得鎖。
2、notify方法
notify方法相當(dāng)于從wait set中從挑出一個(gè)線程并喚醒。
下圖中線程A在當(dāng)前實(shí)例對(duì)象的wait set中等待,此時(shí)線程B必須拿到同一實(shí)例的對(duì)象鎖,才能調(diào)用notify方法喚醒wait set中的任意一個(gè)線程。
注:線程B調(diào)用notify方法后,并不會(huì)立即釋放鎖,會(huì)有一段時(shí)間差。
3、notifyAll方法
notifyAll方法相當(dāng)于將wait set中的所有線程都喚醒。
4、總結(jié)
wait、notify、notifyAll這三個(gè)方法都是java.lang.Object類的方法(注意,不是Thread類的方法)。
若線程沒有拿到當(dāng)前對(duì)象鎖就直接調(diào)用對(duì)象的這些方法,都會(huì)拋出java.lang.IllegalMonitorStateException異常。
obj.wait()是把當(dāng)前線程放到obj的wait set;
obj.notify()是從obj的wait set里喚醒1個(gè)線程;
obj.notifyAll()是喚醒所有在obj的wait set里的線程。
三、線程的狀態(tài)轉(zhuǎn)移當(dāng)創(chuàng)建一個(gè)Thread子類或?qū)崿F(xiàn)Runnable接口類的實(shí)例時(shí),線程進(jìn)入【初始】狀態(tài);
調(diào)用實(shí)例的start方法后,線程進(jìn)入【可執(zhí)行】狀態(tài);
系統(tǒng)會(huì)在某一時(shí)刻自動(dòng)調(diào)度處于【可執(zhí)行】狀態(tài)的線程,被調(diào)度的線程會(huì)調(diào)用run方法,進(jìn)入【執(zhí)行中】狀態(tài);
線程執(zhí)行完run方法后,進(jìn)入【結(jié)束】狀態(tài);
處于【結(jié)束】狀態(tài)的線程,在某一時(shí)刻,會(huì)被JVM垃圾回收;
處于【執(zhí)行中】狀態(tài)的線程,若調(diào)用了Thread.yield方法,會(huì)回到【可執(zhí)行】狀態(tài),等待再次被調(diào)度;
處于【執(zhí)行中】狀態(tài)的線程,若調(diào)用了wait方法,會(huì)進(jìn)入wait set并一直等待,直到被其它線程通過notify、notifyAll、interrupt方法喚醒;
處于【執(zhí)行中】狀態(tài)的線程,若調(diào)用了Thread.sleep方法,會(huì)進(jìn)入【Sleep】狀態(tài),無法繼續(xù)向下執(zhí)行。當(dāng)sleep時(shí)間結(jié)束或被interrupt時(shí),會(huì)回到【可執(zhí)行狀態(tài)】;
處于【執(zhí)行中】狀態(tài)的線程,若遇到阻塞I/O操作,也會(huì)停止等待I/O完成,然后回到【可執(zhí)行狀態(tài)】;
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/71491.html
摘要:文章結(jié)構(gòu)來自七周七并發(fā)模型互斥和內(nèi)存模型創(chuàng)建線程這段代碼創(chuàng)建并啟動(dòng)了一個(gè)實(shí)例,首先從開始,函數(shù)的余下部分一起并發(fā)執(zhí)行。在鎖定狀態(tài)下,某些線程擁有鎖在非鎖定狀態(tài)下,沒有線程擁有它。 并發(fā)&并行 并發(fā)程序含有多個(gè)邏輯上的獨(dú)立執(zhí)行塊,他們可以獨(dú)立的并行執(zhí)行,也可以串行執(zhí)行。并行程序解決問題的速度比串行程序快的多,因?yàn)槠淇梢酝瑫r(shí)執(zhí)行整個(gè)任務(wù)的多個(gè)部分。并行程序可能有多個(gè)獨(dú)立執(zhí)行塊,也可能只有一...
摘要:一并發(fā)和并行并發(fā)是同一時(shí)間應(yīng)對(duì)多件事情的能力并行是同一時(shí)間做多件事情的能力。用并發(fā)的目的,不僅僅是為了讓程序并行運(yùn)行從而發(fā)揮多核的優(yōu)勢(shì)。函數(shù)式編程函數(shù)式編程日漸重要的原因之一,是其對(duì)并發(fā)編程和并行編程提供了良好的支持。 一、并發(fā)和并行: 并發(fā)是同一時(shí)間應(yīng)對(duì)(dealing with)多件事情的能力; 并行是同一時(shí)間做(doing)多件事情的能力。 二、并行架構(gòu): 位級(jí)并行,...
摘要:前言想要進(jìn)入等一線互聯(lián)網(wǎng)公司,以下是你必需具備的技能。包由解釋程序自動(dòng)加載,不需要顯示說明。包包括許多具有特定功能的類,有日期向量哈希表堆棧等,其中類支持與時(shí)間有關(guān)的操作。包定義了應(yīng)用程序編程接口,是應(yīng)用程序環(huán)境的中性平臺(tái)組件結(jié)構(gòu)。 前言 想要進(jìn)入BAT等一線互聯(lián)網(wǎng)公司,以下是你必需具備的技能。如果你掌握的不牢固,那就趕快鞏固,如果你還沒有涉及,現(xiàn)在就立馬學(xué)習(xí)起來吧。 1.Java語言...
閱讀 1280·2023-04-25 18:57
閱讀 2179·2023-04-25 16:28
閱讀 3974·2021-11-24 09:39
閱讀 3664·2021-11-16 11:45
閱讀 1901·2021-10-13 09:40
閱讀 1285·2019-08-30 15:52
閱讀 1759·2019-08-30 10:57
閱讀 687·2019-08-29 16:55