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