day24筆記第24天多線程技術(shù)_第1頁
day24筆記第24天多線程技術(shù)_第2頁
day24筆記第24天多線程技術(shù)_第3頁
day24筆記第24天多線程技術(shù)_第4頁
day24筆記第24天多線程技術(shù)_第5頁
已閱讀5頁,還剩13頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、第 24 天 多線程技術(shù)今日任務(wù)1、多線程技術(shù)介紹2、主線程介紹3、創(chuàng)建線程的方式4、線程中的異常問題5、線程運行狀態(tài)6、線程第二種創(chuàng)建方式7、多線程練習(xí)8、線程安全問題分析和解決9、多線程細(xì)節(jié)10、同步使用的鎖課堂筆記1、多線程技術(shù)介紹1.1、進(jìn)程介紹需要安裝操作系統(tǒng)上,但是在硬盤上。真正要使用某個應(yīng)用,需要啟動這個程序,在啟動程序的時候,其實是在把硬盤上安裝的這個程序加載到計算機的內(nèi)存中。而這個應(yīng)用程序在內(nèi)存占用的是某一部分內(nèi)存區(qū)域。應(yīng)用程序在內(nèi)存中所分配的那個塊內(nèi)存空間稱為當(dāng)前這個應(yīng)用程序在內(nèi)存中的一個進(jìn)程。每個應(yīng)用程序在內(nèi)存都需要一個進(jìn)程,這個進(jìn)負(fù)責(zé)當(dāng)前這個程序的具體運行的細(xì)節(jié)。1.2

2、、線程介紹線程:它表示的是某個程序在運行過程中的一個獨立的運行單元。例如:在運行的時候,需要一個進(jìn)程,但是啟動每個好友窗,每個好友窗口就需要一個獨立運行單元,但是這個單元必須位于當(dāng)前所在的那個進(jìn)程中。這個獨立的單元就是線程。每個進(jìn)程中最少有一個線程。線程是真正實現(xiàn)程序功能的單元。1.3、多線程介紹多線一個程序中,可以開啟這個程序的多條執(zhí)行路徑,這些同時完成某個功能。多線程的目的:提供程序的執(zhí)行效率。1.4、多線程運行的原理計算機中運行的任何程序都需要cpu 去處理,多線程真正的運行原理是靠 cpu 在多個線程之間做著高速的切換。cpu 真正在某個時間點上只能執(zhí)行一個動作,但是由于 cpu 這個

3、硬件它在工作的過程中,可以以很小的時間碎片為在多個線程之間切換,由于切換的速度太快,導(dǎo)致人類無法覺察。如果可以使用多線程完成的任務(wù),是否開啟的線程,可以更好的提高程序的執(zhí)行效率呢?在 cpu 的合理處理能力范圍,開啟多個線程可以提高程序的效率,如果無線開啟線程,會降低程序效率。2、Java 關(guān)于線程的描述Java 語言它會使用不同的類,接口等內(nèi)容把生活中、計算機等領(lǐng)取中的事物等信息全部抽取出來,使用 Java中的對應(yīng)的類或接口進(jìn)行封裝和描述。 “sdhsdkljfklsd”String計算機中保存數(shù)據(jù)的文件,或者管理文件的文件夾操作文件中的數(shù)據(jù)IO 流對象File真正在開發(fā)的時候,是使用 Ja

4、va 中提供好的這些類或者接口完成最終需要的結(jié)果。后期的所有學(xué)習(xí),都是在熟悉一些 API,然后使用這些 API,完成工作的任務(wù)。線程是任務(wù)事物的描述。中必須存在的一類事物(主要負(fù)責(zé)程序的運行),Java 中提供了 Thread 類專門負(fù)責(zé)線程這個2.1、主線程介紹書寫的 Java 程序,是由 JVM 負(fù)責(zé)運行,而 JVM 在運行程序的時候,需要找到某個類中的 main 方法進(jìn)行運行。也就是說 JVM 中會開啟一個線程專門負(fù)責(zé)從 main 開始運行的代碼, 而負(fù)責(zé)從 main 開始運行代碼的那個線程序中稱為主線程。2.2、Thread 類介紹Thread 是程序中的執(zhí)行線程。Java 虛擬機允許

5、應(yīng)用程序并發(fā)地運行多個執(zhí)行線程。每多一個 Thread 對象,就表示多了一個線程對象。這時就應(yīng)該可以通過 Thread 去操作當(dāng)前這個線程對象。API 中告訴創(chuàng)建線程有 2 種方式:第一種:1、定義一個類繼承 Thread2、子類復(fù)寫 Thread 類中的 run 方法3、創(chuàng)建子類對象(子類就是一個線程類)4、啟動子類對象2.3、繼承 Thread 的原理2.3.1、為什么要繼承 Thread 類?線程是計算機中程序運行的一個獨立單元,這個單元 Java 使用 Thread 類進(jìn)行了描述?,F(xiàn)在需要自己使用線程,執(zhí)行自己的某些代碼。Thread 類是 Java 中提供的原生的類,而具體需要操作線

6、程時,不能直接去使用 Thread,如果直接去使用的 Thread,導(dǎo)致原生的 Thread 類無法知道后期真正需要讓線程執(zhí)行的代碼。API 中告訴需要自己定義一個類繼承 Thread,自己的類繼承了 Thread 那么自己的類就變成線程類,就繼承到 Thread 類中的所有功能,自己的類就可以去使用 Thread 類中定義的所有操作線程的功能。/* 演示創(chuàng)建線程的第式*/定義子類,繼承 Threadclass Demo extends Thread/復(fù)寫 run 方法public void run()for(i=0;i20;i+ )System.out.prln(demo run i = +

7、i);public class ThreadDemo public sic void main(String args) /創(chuàng)建子類對象Demo d = new Demo();/啟動線程 d.start();for(i=0;i20;i+ ) System.out.prln(main i = +i);繼承 Thread 類的目的就是讓自己的類變成線程類??梢匀ゲ僮骶€程。2.3.2、為什么要復(fù)寫 run 方法開啟線程的目的是讓多部分代碼同時運行,讓線程去執(zhí)行自己的某些代碼,而這些代碼需要交給線程運行,那么就必須按照線程運行時會調(diào)用的某些固定的功能。當(dāng)而調(diào)用 start 方法的時候,JVM 在底層會

8、自動的調(diào)用 run 方法,而 run 方法中的代碼就會被某個線程去執(zhí)行。開啟線程的某地就是希望線程執(zhí)行某些代碼,也就是只要大家把需要線程執(zhí)行的代碼書寫在 run 方法中,一旦開啟線程,run 方執(zhí)行。自動的運行過,那么就會 導(dǎo)致 書寫在 run 方法中的所有代碼會被當(dāng)前某個線程去調(diào)用復(fù)寫 run 方法的目的:就是希望在 run 方法中書寫線程要執(zhí)行的那么代碼。線程要執(zhí)行的代碼:稱為線程的任務(wù)。2.3.3、為什么不直接調(diào)用 run 方法,而調(diào)用 start 方法如果直接調(diào)用 run 方法,這時雖然有線程對象,但是并沒有讓線程真正開啟,而不開啟線程,直接通過線程對象調(diào)用 run 方法,這個和的區(qū)域

9、中運行。以前學(xué)習(xí)的對象調(diào)用普通方法沒有任何區(qū)別,這些調(diào)用的功能都會在主線程所在如果有了線程對象,希望線程可以獨立去運行,只能手動調(diào)用 Thread 類提供的 start 方法,才能在棧內(nèi)存中開啟一個新的執(zhí)行通道(路徑),這樣才能保證 run 方被加載到新的執(zhí)行路徑中去運行。3、開啟線程的第二種方式3.1、實現(xiàn) Runnable 接口的步驟1、定義一個類 實現(xiàn) Runnable 接口2、實現(xiàn)接口中的 run 方法3、創(chuàng)建實現(xiàn)類的對象4、創(chuàng)建 Thread 對象,把實現(xiàn)類對象作為參數(shù)傳遞5、開啟線程/* 演示創(chuàng)建線程的第二種方式*/class Demo2 implements Runnable/實

10、現(xiàn) run 方法public void run() for(i=0;i20;i+ )3.2、實現(xiàn) Runnable 接口的原理1、Java 中繼承的局限性Java 只支持單繼承,不支持多繼承。如果一個類已經(jīng)有父類了,但這個類中有部分代碼需要多線程操作,這時就沒有辦法再讓這個類去繼承 Thread。也就是 Java 中提供的第線程了。式就無法使用。導(dǎo)致沒有辦法去操作多Thread 類是描述線程,Thread 類就應(yīng)該只定義如何去操作線程的功能,在 Thread 中提供了一個 run 方法,而這個 run 方法是專門用來明確線程要執(zhí)行的任務(wù)的方法。于是就 run 方法從 Thread 類中出來,專

11、門定義了一個接口,后期真正在開發(fā)中,如果要明確線程的任務(wù),找對應(yīng)的接口,如果要操作線程就直接找 Thread。2、Java 中提供的接口的作用、給事物體現(xiàn)添加(增加)擴展功能。、給事物雙方定義規(guī)則。Runnable 接口它其實是在定義線程中操作任務(wù)的一個規(guī)則。線程是可以操作任務(wù)的,而任務(wù)是需要后來程序書寫和明確的。只有明確的任務(wù)符合 Runnable 接口的規(guī)范,那么 Thread 才能去真正調(diào)用 run 方法。3、其他的技術(shù)問題:1、在創(chuàng)建 Thread 類的時候,其實只是明確了線程對象2、書寫的實現(xiàn)了 Runnable 接口的類,相當(dāng)于明確了線程要執(zhí)行的任務(wù)類,當(dāng)于明確了線程要執(zhí)行的任務(wù)對

12、象。創(chuàng)建了實現(xiàn)類對象,就相當(dāng)System.out.prln(demo2 run i = +i);public class ThreadDemo2 public sic void main(String args) /創(chuàng)建實現(xiàn)類的對象Demo2 d = new Demo2();/創(chuàng)建 Thread 對象Thread t = new Thread( d );/開啟線程 t.start();for(i=0;i 0 )/判斷成立表示當(dāng)前有票+ 當(dāng)前正在售出的票號:System.out.prln( Thread.currentThread().getName()+num);num-;public cla

13、ss ThreadTest public sic void main(String args) /創(chuàng)建線程要執(zhí)行的任務(wù) Ticket task = new Ticket();/創(chuàng)建線程對象ThreadThread Thread Threadt = new Thread( task );t2t3 t4=newnew newThread(Thread( Thread(tasktask task);););/開啟線程 t.start();t2.start();t3.start();t4.start();6、多線程安全問題分析上述的代碼有問題:在運行的過程會出現(xiàn)某些票號在重復(fù)。多線程的安全問題是因為

14、CPU 在多個線程的任務(wù)中會隨機切換造成的。真正導(dǎo)致多線程安全問題發(fā)生的本質(zhì)是 cpu 切換造成的,但是在的程序中多個線操作共享的數(shù)據(jù)。由于某個線程正在操作共享數(shù)據(jù)的時候,還沒有徹底操作完成,cpu 切換到其他的線進(jìn)行修改,導(dǎo)致 cpu 再切換回來時共享的數(shù)據(jù)就和以前的真實數(shù)據(jù)不一致。,而其他線程對共享的數(shù)據(jù)7、多線程安全問題解決多線程的解決方案:Java 給提供了解決方案:同步代碼塊。同步:所有的操作必須按照先后的次序進(jìn)行。前面沒有執(zhí)行完,后面的必須等待。例如:上廁所。同步代碼塊的格式:synchronized( 鎖對象 )需要被同步的代碼/* 模擬售票*/class Ticket2 imp

15、lements Runnable/定義一個變量,用來充當(dāng)某趟列車的總票數(shù)privatenum = 100;8、同步的細(xì)節(jié)1、同步的好處:可以保證多線操作共享數(shù)據(jù)時的安全。2、不同的弊端:降低了程序的執(zhí)行效率。3、同步代碼塊上使用的鎖可以是任意對象。4、如果添加了同步,安全問題依然發(fā)生,怎么解決?a、首先查看同步代碼塊添加的位置是否在操作共享數(shù)據(jù)的代碼上。 b、查看同步使用的鎖是否是同一把(唯一)。前面學(xué)習(xí)過的和線程相關(guān)的 api: StringBuffer:多線程操作時是安全的。StringBuilder:單線程操作效率較高。多線程操作不安全。JDK1.0 中出現(xiàn)的下面 2 個集合都是線程安全

16、的,他們的效率都很低。Vector:被 ArrayList 代替Hashtable:被 HashMap 代替JDK1.2 之后出現(xiàn)的所有集合線程都是不安全的。如果程序中需要線程安全的集合,這時請使用 Collections 中/創(chuàng)建一個公用的鎖對象private Object lock = new Object();public void run()/在 run 方法中售票while( true )/*書寫死循環(huán)的目的是表示某個窗口一旦開始售票,就不會停止,一直在售票*/ t1/t2/t3synchronized( lock ) /線程首先需要獲取鎖對象if( num 0 )/判斷成立表示當(dāng)前

17、有票System.out.prln( Thread.currentThread().getName() + 當(dāng)前正在售出的票號:+num);num-;/ 執(zhí)行到這里,某個線程就出了同步代碼塊,首先需要自己持有的鎖/ t0-的把集合變成安全集合的方法:9、單例懶漢式多線程安全問題單例設(shè)計模式:保證當(dāng)前這個類的對象唯一。單例的書寫步驟:1、私有本類的構(gòu)造方法2、創(chuàng)建本類對象3、對外提供獲取本類對象的方法常見的 2 種代碼書寫形式:餓漢式:class Singleprivate Single()private sic final Single instance = new Single();publ

18、ic sic Single getInstance() return instance;懶漢式:class Singleprivate Single()private sic Single instance = null;public sic Single getInstance()if( instance = null )instance = new Single();return instance;多線程的安全問題分析:1、有多個線程。2、有共享的數(shù)據(jù)。同時多個線程對共享的數(shù)據(jù)有修改等操作。/* 單例懶漢式的多線程操作的安全問題*/class Single /創(chuàng)建一個鎖對象private

19、sic Object lock = new Object();private Single() private sic Single instance = null; public sic Single getInstance() /* 同步外面添加的這個判斷,目的是提高后續(xù)線程來獲取對象時的效率*/if( instance = null )/加同步的目的保證對象的唯一synchronized( lock )if (instance = null) instance = new Single();return instance;/測試多線程操作單例的懶漢式的安全問題class Demo imp

20、lements Runnablepublic void run() System.out.prln(Single.getInstance();10、多線程中的死鎖問題死鎖:在程序執(zhí)行的過程中,因為鎖的獲取和出現(xiàn)了問題,導(dǎo)致程序停留在某個代碼處無法往下執(zhí)行。常見的一種死鎖現(xiàn)象:假設(shè)有 2 個線程:需要執(zhí)行相同的任務(wù),但是需要獲取不同的鎖才能執(zhí)行。Thread-0Thread-1線程線程必須 先獲取 A 鎖,再獲取 B 鎖,然后才能去執(zhí)行任務(wù)。必須 先獲取 B 鎖,在獲取 A 鎖,然后才能去執(zhí)行任務(wù)?,F(xiàn)在發(fā)生了 Thread-0 正好獲取到 A 鎖,cpu 切換到 Thread-1 線,這時 Th

21、read-1 就獲取到 B 鎖,接下來不管 cpu 切換到那個線,都需要獲取對方手上持有的那個鎖。/* 演示死鎖*/class Demo2 implements Runnable/定義 2 個鎖對象private Object lock_A = new Object();private Object lock_B = new Object();/定義一個標(biāo)記,目的是讓 2 個線程可以到不同的地方去運行publicflag = false; public void run() /判斷標(biāo)記,目的是切換線程到不同的代碼區(qū)域中去運行if( flag )while(true)/添加同步代碼塊synchr

22、onized (lock_A) public class ThreadDemo public sic void main(String args) Demo d = new Demo();Thread t = new Thread(d); Thread t2 = new Thread(d);t.start();t2.start();ln( if +Thread.currentThread().getName() +線程獲取到的System.out.prlock_A 鎖);synchronized (lock_B) System.out.prln( if +Thread.currentThrea

23、d().getName() +線程獲取到的 lock_B 鎖);/任務(wù)elsewhile(true)/添加同步代碼塊synchronized (lock_B) ln( else +Thread.currentThread().getName() +.線System.out.pr程獲取到的 lock_B 鎖);synchronized (lock_A) System.out.pr+.線程獲取到的 lock_A 鎖);/任務(wù)ln( else +Thread.currentThread().getName()public class DeadLock public sic void main(Str

24、ingargs) throwserruptedException /創(chuàng)建任務(wù)對象Demo2 d = new Demo2();Thread t = new Thread(d);Thread t2 = new Thread(d);t.start();/* 在開啟 Thread-0 線程之后,需要人為的去修改這個標(biāo)記,* 目的是讓另外一個線程可以進(jìn)入到和 Thread-0 不同的地方運行* 在執(zhí)行 t.start 方法的時候,是在主線執(zhí)行的,雖然開啟了 Thread-0 線程這時內(nèi)存中有 2 個線程,分別是:main 和 Thread-0 線程,如果 cpu 還在 main 線那么就會直接把 fla

25、g 修改為 true,如果在修改完之后,cpu 才切換到 Thread-0 線這時 Thread-0 一定會執(zhí)行 if 代碼。*,11、同步中鎖線程有安全問題,需要加同步代碼塊,而同步代碼塊上使用的鎖是任意的對象。同步不僅僅可以使用同步代碼塊,還可以使用同步方法(可以把同步直接添加在方法上)。格式:修飾符 添加同步 返回值類型 方法名( 參數(shù)類型 參數(shù)名,參數(shù)類型 參數(shù)名 )方法體如果把同步添加在方法上,導(dǎo)致當(dāng)前這個方法中的所有代碼全部被同步,任何線程要進(jìn)入這個方法,都需要先獲取鎖對象。主要介紹:方法上的同步,它們使用的鎖到底是誰?非靜態(tài)方法上的鎖和靜態(tài)方法上的鎖:/* 方法上的鎖對象演示*/

26、class Ticket implements Runnable/定義一個變量,用來充當(dāng)某趟列車的總票數(shù)private sicnum = 100; private Object lock = new Object(); publicflag = false;public void run()if( flag )/在 run 方法中售票while( true )synchronized( Ticket.class )if( num 0 )/判斷成立表示當(dāng)前有票為了保證 cpu 一定可以切換到 Thread-0 上,人為的讓主線開啟 Thread-0 之后,休眠一定的時間。*/ Thread.sl

27、eep(1); d.flag = true;t2.start();ln( Thread.currentThread().getName() + 當(dāng)前正在售出的System.out.pr票號:+num);num-;elsewhile( true )show();/*如果一個方法中的所有代碼都在操作共享的數(shù)據(jù),這時可以把同步直接添加在方法上。非靜態(tài)方法上的鎖是當(dāng)前調(diào)用這個方法的那個對象,在 Java 中可以使用 this 表示靜態(tài)方法上使用的鎖是當(dāng)前這個方法所屬的那個類(類名的.class)*/public sic synchronized void show()if( num 0 )/判斷成立表

28、示當(dāng)前有票System.out.prln( Thread.currentThread().getName() + 當(dāng)前正在售出的票號:+num);num-;public class ThreadTest public sic void main(String args) throwserruptedException /創(chuàng)建線程要執(zhí)行的任務(wù) Ticket task = new Ticket();/創(chuàng)建線程對象Thread t = new Thread( task );Thread t2 = new Thread( task );/開啟線程 t.start(); Thread.sleep(1); task.flag = true;t2.start();System.out.prln(over.);總結(jié)鎖的使用:1、同步代碼塊上的鎖是任意對象

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論