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

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

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

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

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

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

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

6、程時,不能直接去使用 Thread,如果直接去使用的 Thread,導致原生的 Thread 類無法知道后期真正需要讓線程執(zhí)行的代碼。API 中告訴需要自己定義一個類繼承 Thread,自己的類繼承了 Thread 那么自己的類就變成線程類,就繼承到 Thread 類中的所有功能,自己的類就可以去使用 Thread 類中定義的所有操作線程的功能。/* 演示創(chuàng)建線程的第式*/定義子類,繼承 Threadclass Demo extends Thread/復寫 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、為什么要復寫 run 方法開啟線程的目的是讓多部分代碼同時運行,讓線程去執(zhí)行自己的某些代碼,而這些代碼需要交給線程運行,那么就必須按照線程運行時會調用的某些固定的功能。當而調用 start 方法的時候,JVM 在底層會

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

9、中運行。以前學習的對象調用普通方法沒有任何區(qū)別,這些調用的功能都會在主線程所在如果有了線程對象,希望線程可以獨立去運行,只能手動調用 Thread 類提供的 start 方法,才能在棧內存中開啟一個新的執(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 中提供的第線程了。式就無法使用。導致沒有辦法去操作多Thread 類是描述線程,Thread 類就應該只定義如何去操作線程的功能,在 Thread 中提供了一個 run 方法,而這個 run 方法是專門用來明確線程要執(zhí)行的任務的方法。于是就 run 方法從 Thread 類中出來,專

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

12、象。創(chuàng)建了實現(xiàn)類對象,就相當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 )/判斷成立表示當前有票+ 當前正在售出的票號:System.out.prln( Thread.currentThread().getName()+num);num-;public cla

13、ss ThreadTest public sic void main(String args) /創(chuàng)建線程要執(zhí)行的任務 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)某些票號在重復。多線程的安全問題是因為

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

15、lements Runnable/定義一個變量,用來充當某趟列車的總票數(shù)privatenum = 100;8、同步的細節(jié)1、同步的好處:可以保證多線操作共享數(shù)據(jù)時的安全。2、不同的弊端:降低了程序的執(zhí)行效率。3、同步代碼塊上使用的鎖可以是任意對象。4、如果添加了同步,安全問題依然發(fā)生,怎么解決?a、首先查看同步代碼塊添加的位置是否在操作共享數(shù)據(jù)的代碼上。 b、查看同步使用的鎖是否是同一把(唯一)。前面學習過的和線程相關的 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 )/判斷成立表示當前

17、有票System.out.prln( Thread.currentThread().getName() + 當前正在售出的票號:+num);num-;/ 執(zhí)行到這里,某個線程就出了同步代碼塊,首先需要自己持有的鎖/ t0-的把集合變成安全集合的方法:9、單例懶漢式多線程安全問題單例設計模式:保證當前這個類的對象唯一。單例的書寫步驟:1、私有本類的構造方法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)了問題,導致程序停留在某個代碼處無法往下執(zhí)行。常見的一種死鎖現(xiàn)象:假設有 2 個線程:需要執(zhí)行相同的任務,但是需要獲取不同的鎖才能執(zhí)行。Thread-0Thread-1線程線程必須 先獲取 A 鎖,再獲取 B 鎖,然后才能去執(zhí)行任務。必須 先獲取 B 鎖,在獲取 A 鎖,然后才能去執(zhí)行任務?,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();/定義一個標記,目的是讓 2 個線程可以到不同的地方去運行publicflag = false; public void run() /判斷標記,目的是切換線程到不同的代碼區(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 鎖);/任務elsewhile(true)/添加同步代碼塊synchronized (lock_B) ln( else +Thread.currentThread().getName() +.線System.out.pr程獲取到的 lock_B 鎖);synchronized (lock_A) System.out.pr+.線程獲取到的 lock_A 鎖);/任務ln( else +Thread.currentThread().getName()public class DeadLock public sic void main(Str

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

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

26、class Ticket implements Runnable/定義一個變量,用來充當某趟列車的總票數(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 )/判斷成立表示當前有票為了保證 cpu 一定可以切換到 Thread-0 上,人為的讓主線開啟 Thread-0 之后,休眠一定的時間。*/ Thread.sl

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

28、示當前有票System.out.prln( Thread.currentThread().getName() + 當前正在售出的票號:+num);num-;public class ThreadTest public sic void main(String args) throwserruptedException /創(chuàng)建線程要執(zhí)行的任務 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.);總結鎖的使用:1、同步代碼塊上的鎖是任意對象

溫馨提示

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

評論

0/150

提交評論