CPU同一個時刻執(zhí)行一個程序劫笙,一個進(jìn)程中可能出現(xiàn)多條執(zhí)行路徑,也就是線程沼撕。
線程是進(jìn)程的控制單元,是進(jìn)程中真正執(zhí)行的部分张峰。線程控制進(jìn)程的執(zhí)行。一個進(jìn)程至少有一個線程負(fù)責(zé)程序的執(zhí)行棒旗,而且這個線程運(yùn)行的代碼存在于main中喘批,稱為主線程。
其實jvm啟動不止一個線程铣揉,還有負(fù)責(zé)垃圾回收機(jī)制的線程饶深,是多線程的。
Thread類:程序中的執(zhí)行線程逛拱。允許程序并發(fā)運(yùn)行多個線程
創(chuàng)建線程:1.繼承Thread類敌厘,覆蓋run方法,創(chuàng)立新對象等于創(chuàng)建好一個線程朽合,啟動線程則調(diào)用start方法(啟動線程俱两,調(diào)用run方法)
在一個進(jìn)程中CPU也要進(jìn)行線程的切換饱狂,搶到CPU執(zhí)行權(quán)就先執(zhí)行。運(yùn)行結(jié)果每一次都不同锋华,因為多個線程都獲取cpu的執(zhí)行權(quán)嗡官,在某一時刻只能有一個程序在運(yùn)行(單核)箭窜。
run方法定義了一個功能毯焕,用于儲存線程要運(yùn)行的代碼。虛擬機(jī)定義主線程要調(diào)用的代碼在main方法中磺樱。
復(fù)寫run的目的是:將自定義代碼存儲在run方法中纳猫,讓線程運(yùn)行。而start的功能是啟動線程并調(diào)用run竹捉。僅僅使用run是封裝線程執(zhí)行的代碼芜辕,即使線程創(chuàng)建了卻沒有運(yùn)行線程。
static Thread currentThread():獲取當(dāng)前線程對象
getName():獲取線程名稱
線程名稱:setName或用構(gòu)造函數(shù)傳入
局部變量在每一個線程內(nèi)存中都有獨(dú)立的一份块差。
多線程例子:售票侵续,多窗口賣票
runnable接口:創(chuàng)建線程的第二種方式
1.定義類實現(xiàn)runnable接口
2.覆蓋runnable中的run方法:線程要運(yùn)行的代碼
3.通過Thread類建立線程對象
4.將runnable接口的子類對象作為Thread的參數(shù)傳遞其構(gòu)造函數(shù)(因為run方法所屬的對象是Runnable類,讓線程指定對象的run方法憨闰,就必須明確run方法的對象)
5.調(diào)用Thread類的start方法并開啟線程状蜗、調(diào)用runnable接口子類的run方法
實現(xiàn)方式和繼承方式的區(qū)別:實現(xiàn)方式使多線程成為擴(kuò)展功能,避免了單繼承局限性鹉动。而繼承之后該類就不能成為其他類的子類轧坎。繼承thread:線程代碼存放在Thread的子類中,而runnable代碼存放在接口的子類的run方法中泽示。
安全隱患:多線程可能會跳過判斷而出現(xiàn)不合理的結(jié)果缸血,需要停一下⌒瞪福可能測試不出問題捎泻,但是實際運(yùn)行出現(xiàn)問題。
try{Thread.sleep(10);} catch(Exception e){? }
注意:實現(xiàn)接口的方法的異常不能throw埋哟,只能try族扰。
問題原因:當(dāng)多條語句在操作同一個線程共享數(shù)據(jù)時,一個線程對多條語句只執(zhí)行一部分定欧,但是另一個線程參與進(jìn)來執(zhí)行渔呵,導(dǎo)致共享數(shù)據(jù)的錯誤。
解決辦法:對多條操作共享數(shù)據(jù)的語句砍鸠,只能一個線程執(zhí)行完扩氢,再執(zhí)行過程中其他線程。
同步代碼塊:
synchronized(對象)
????{需要被同步的代碼爷辱,也就是操作共享數(shù)據(jù)的語句}
鎖:對象有兩個標(biāo)志位0,1录豺,當(dāng)0線程獲得執(zhí)行權(quán)就判斷標(biāo)志位朦肘。如果是1,就進(jìn)入代碼双饥,將1變成0媒抠,執(zhí)行代碼塊。執(zhí)行完后又把標(biāo)志位改1咏花。對象如同鎖趴生,持有鎖的線程可以在同步中執(zhí)行。沒有鎖的線程即使獲取cpu執(zhí)行權(quán)也進(jìn)不去昏翰,因為沒有鎖苍匆。
同步的前提:必須要有多個線程;必須的多個線程使用同一個鎖棚菊;必須保證同步中只能有一個線程進(jìn)行浸踩。
好處:解決多線程安全問題;弊端:判斷消耗資源
找問題:明確哪些代碼是多線程運(yùn)行代碼统求;明確共享數(shù)據(jù)检碗;明確多線程中哪些語句操作共享數(shù)據(jù);
同步函數(shù):修飾符synchronized修飾函數(shù)起到同步效果
可以將有需要的代碼變成函數(shù)封裝成同步函數(shù)码邻。
函數(shù)需要被對象調(diào)用折剃,同步函數(shù)的鎖是this
多線程中還有主線程,可能會啟動其他線程并操作共享數(shù)據(jù)冒滩,從而影響了一開始啟動的線程微驶。可以讓主線程先sleep一下开睡。實例中使用了兩種不同的同步:同步函數(shù)和同步代碼塊因苹。因為兩個方式的鎖不一致,所以出現(xiàn)了錯誤篇恒。
靜態(tài)同步函數(shù):靜態(tài)同步函數(shù)所用的鎖不是this扶檐,類要先封裝成對象(字節(jié)碼文件對象)該對象的類型是class,鎖是該方法所在類對應(yīng)的字節(jié)碼文件對象胁艰。
死鎖
同步中嵌套同步款筑,144,一個線程同步中拿著A對象想要調(diào)用B對象腾么,而另一個線程同步中拿著B對象想要調(diào)用A對象