1佛点、基本概念描述
首先區(qū)分進(jìn)程和線程的概念:
進(jìn)程——即正在運(yùn)行的程序灼捂,負(fù)責(zé)了這個程序的內(nèi)存空間分配片吊,代表了內(nèi)存中的執(zhí)行區(qū)域。
線程——就是在一個進(jìn)程中負(fù)責(zé)一個執(zhí)行路徑把还。
比如在用某60清理電腦時实蓬,一鍵優(yōu)化與垃圾清除同時在運(yùn)行,這時在一個進(jìn)程中就同時在執(zhí)行了多個任務(wù)——多線程(一個進(jìn)程中多個執(zhí)行路徑同時執(zhí)行)
多線程的好處:
1.解決了一個進(jìn)程里面可以同時運(yùn)行多個任務(wù)(執(zhí)行路徑)吊履。
2.提高資源的利用率(注意并不是提高效率)安皱。
多線程的弊端:
1.降低了一個進(jìn)程里面的線程的執(zhí)行頻率。
2.對線程進(jìn)行管理要求額外的CPU開銷艇炎。線程的使用會給系統(tǒng)帶來上下文切換的額外負(fù)擔(dān)酌伊。
3.當(dāng)多個線程需要對公有變量進(jìn)行寫操作時,后一個線程往往會修改掉前一個線程存放的數(shù)據(jù)缀踪,發(fā)生線程安全問題居砖。
4.即較長時間的等待或資源競爭以及死鎖等多線程癥狀。
進(jìn)程的假象
“多任務(wù)”操作系統(tǒng)能同時運(yùn)行多個進(jìn)程(程序)——但實(shí)際是由于CPU分時機(jī)制的作用驴娃,使每個進(jìn)程都能循環(huán)獲得自己的CPU時間片奏候。但由于輪換速度非常快唇敞,使得所有程序好象是在“同時”運(yùn)行一樣蔗草。
2、Java中創(chuàng)建線程的方式
2.1疆柔、方式一:繼承Thread類
創(chuàng)建步驟:
1. 自定義一個類繼承Thread類咒精。
2. 重寫Thread類的run方法 , 把自定義線程的任務(wù)代碼寫在run方法中
3. 創(chuàng)建Thread的子類對象,并且調(diào)用start方法開啟線程旷档。
具體例子如下
注意:一個線程一旦開啟狠轻,那么線程就會執(zhí)行run方法中的代碼,run方法千萬不能直接調(diào)用彬犯,直接調(diào)用run方法就相當(dāng)調(diào)用了一個普通的方法而已向楼,并沒有開啟新的線程。
常用方法:
Thread(String name) ——初始化線程的名字
setName(String name)——設(shè)置線程對象名
getName()——返回線程的名字
sleep()——線程睡眠指定的毫秒數(shù)谐区,靜態(tài)方法
currentThread() ——返回當(dāng)前的線程對象湖蜕,靜態(tài)方法
getPriority()——返回當(dāng)前線程對象的優(yōu)先級,默認(rèn)線程的優(yōu)先級是5(最大的優(yōu)先級是10宋列,最小的1)
setPriority(int newPriority)——設(shè)置線程的優(yōu)先級昭抒。雖然設(shè)置了線程的優(yōu)先級,但是具體的實(shí)現(xiàn)取決于底層的操作系統(tǒng)的實(shí)現(xiàn)
通過一個實(shí)例來體會以上方法
首先我們自定義一個線程
接著在主函數(shù)中實(shí)例化這個線程,并嘗試調(diào)用之前所述的方法
控制臺輸出結(jié)果如下
自定義線程的優(yōu)先級:10
當(dāng)前線程對象:Thread[鐵蛋,10,main]
主線程的優(yōu)先級:5
主線程的名字:main
線程同步機(jī)制
如之前所講灭返,當(dāng)多個線程需要對公有變量進(jìn)行寫操作時盗迟,后一個線程往往會修改掉前一個線程存放的數(shù)據(jù),發(fā)生線程安全問題熙含。
出現(xiàn)線程安全問題的根本原因:
1. 存在兩個或者兩個以上的線程對象罚缕,而且線程之間共享著一個資源。
2. 有多個語句操作了共享資源怎静。
sun公司提供了線程同步機(jī)制讓我們解決這類問題邮弹。
實(shí)現(xiàn)同步機(jī)制有兩種方式:同步代碼塊與同步函數(shù),下面來看一個利用同步代碼塊實(shí)現(xiàn)同步機(jī)制的經(jīng)典案例蚓聘。
需求: 模擬3個窗口同時在售50張票
定義一個售票線程
主函數(shù)創(chuàng)建三個售票窗口
同步代碼塊要注意事項(xiàng):
1. 任意的一個對象都可以做為鎖對象腌乡。
2. 只有真正存在線程安全問題的時候才使用同步代碼塊,否則會降低效率的夜牡。
3. 多線程操作的鎖對象必須是唯一共享的与纽,否則無效。(例子中的“鎖”在字符串常量池中塘装,唯一且共享)
死鎖現(xiàn)象:
java中同步機(jī)制解決了線程安全問題急迂,但是也同時引發(fā)死鎖現(xiàn)象。
死鎖現(xiàn)象出現(xiàn) 的根本原因:
1. 存在兩個或者兩個以上的線程氢哮。
2. 存在兩個或者兩個以上的共享資源。
死鎖現(xiàn)象的解決方案: 沒有方案型檀,只能盡量避免發(fā)生而已冗尤。
2.2、方式二:自定義類實(shí)現(xiàn)Runnable接口
創(chuàng)建步驟
1. 自定義一個類實(shí)現(xiàn)Runnable接口胀溺。
2. 實(shí)現(xiàn)Runnable接口的run方法裂七,把自定義線程的任務(wù)定義在run方法上。
3. 創(chuàng)建Runnable實(shí)現(xiàn)類對象仓坞。
4. 創(chuàng)建Thread類的對象背零,并且把Runnable實(shí)現(xiàn)類的對象作為實(shí)參傳遞。
5. 調(diào)用Thread對象的start方法開啟一個線程无埃。
注意:Runnable實(shí)現(xiàn)類的對象并不是一個線程對象徙瓶,只不過是實(shí)現(xiàn)了Runnable接口的對象而已。只有是Thread或者是Thread的子類才是線程對象嫉称。
例子如下:
3侦镇、線程間通訊
線程通訊指的是:一個線程完成了自己的任務(wù)時,要通知另外一個線程去完成另外一個任務(wù)
線程間通訊主要通過以下幾個方法實(shí)現(xiàn):
wait()——如果線程執(zhí)行了wait方法织阅,那么該線程會進(jìn)入等待的狀態(tài)壳繁,等待狀態(tài)下的線程必須要被其他線程調(diào)用notify方法才能喚醒。
notify()——喚醒線程池等待線程其中的一個。
notifyAll() ——喚醒線程池所有等待線程闹炉。
wait與notify方法要注意的事項(xiàng):
1. wait方法與notify方法是屬于Object對象的蒿赢。
2. wait方法與notify方法必須要在同步代碼塊或者是同步函數(shù)中才能使用。
3. wait方法與notify方法必需要由鎖對象調(diào)用渣触。