什么是進程?
進程就是正在運行的應(yīng)用程序
什么是線程?
線程是程序執(zhí)行的一條路徑, 一個進程中可以包含多條線程
多線程并發(fā)執(zhí)行可以提高程序的效率, 可以同時完成多項工作
一個進程至少包含一個線程丑搔,線程控制著進程
?什么是執(zhí)行路徑
一個應(yīng)用程序從執(zhí)行到結(jié)束的整個過程稱為執(zhí)行路徑
多線程并行和并發(fā)的區(qū)別(了解)
并行就是兩個任務(wù)同時運行啤月,就是甲任務(wù)進行的同時谎仲,乙任務(wù)也在進行郑诺。(需要多核CPU)
并發(fā)是指兩個任務(wù)都請求運行辙诞,而處理器只能按受一個任務(wù)飞涂,就把這兩個任務(wù)安排輪流進行,由于時間間隔較短士八,使人感覺兩個任務(wù)都在運行。
例1:一共啟動兩個線程:一個線程用來執(zhí)行main方法里面的代碼(主線程)官卡,另一個用來進行垃圾回收
創(chuàng)建線程的幾種方式:
① 繼承Thread
好處是:可以直接使用Thread類中的方法,代碼簡單
弊端是:如果已經(jīng)有了父類,就不能用這種方法
②實現(xiàn)Runnable接口
好處是:即使自己定義的線程類有了父類也沒關(guān)系,因為有了父類也可以實現(xiàn)接口,而且接口是可以多實現(xiàn)的
弊端是:不能直接使用Thread中的方法需要先獲取到線程對象后,才能得到Thread的方法,代碼復(fù)雜
①class? A extends Thread{?
重寫run方法
}
A a =new? A();
a.start();
②class? A implements Runnable{
重寫run方法
}
A a = new A();
new Thread(a).start();
③匿名內(nèi)部類方式
Runnable runnable?= new Runnable(){
重寫run方法
}
new Thread(runnable).start();
④Thread t1 = new Thread(){
重寫run方法
}评甜;
t1.start;
⑤new Thread(new Runnable(){
重寫run方法
}).start()粘舟;
⑥new Thread(){
重寫run方法
}.start()柑肴;
線程的結(jié)果為什么交叉晰骑?
跟java線程調(diào)度方式有關(guān):java的方式:搶占式
java虛擬機讓當(dāng)前線程暫時放棄cpu硕舆,轉(zhuǎn)到就緒狀態(tài)抚官,使其他線程獲得機會
注意:main方法的結(jié)束代表主線程的結(jié)束
run方法的結(jié)束代表著自己創(chuàng)建的線程結(jié)束
1.在任何一個地方都可以去創(chuàng)建線程
2.線程 只能通過start()凌节;
3.無論在哪創(chuàng)建的線程都是獨立的洒试,與主線程平行
獲取線程名字:?通過getName()方法獲取線程對象的名字
設(shè)置線程名字: 通過setName()方法獲取線程對象的名字
匿名內(nèi)部線程設(shè)置名字:
獲取當(dāng)前線程:Thread.currentThread();
可以通過該方式獲取實現(xiàn)Runnable接口的線程的名字:Thread.currentThread().getName();例:
線程休眠:Thread.sleep();括號內(nèi)為線程休眠時間? 毫秒
插入線程:
插入線程:? Thread? t1 = new Thread()跷坝;
t1.join();在括號寫數(shù)字就是插隊多長時間
守護線程 : t2.setDaemon(true);//將t2設(shè)置為守護線程? ? 當(dāng)非守護線程掛了,那么守護線程就結(jié)束
禮讓線程(只是了解):
yield讓出cpu
設(shè)置線程的優(yōu)先級(只是了解):
setPriority()設(shè)置線程的優(yōu)先級:數(shù)字越大優(yōu)先級越高贴届,優(yōu)先級高只能保證有更多的機會去搶占cpu毫蚓。優(yōu)先級最大是10元潘,最小是1翩概。
同步代碼塊:
線程安全的代碼塊就是同步代碼塊
線程安全就是無論什么時候去訪問結(jié)果都是正確的
1.什么情況下需要同步
當(dāng)多線程并發(fā), 有多段代碼同時執(zhí)行時, 我們希望某一段代碼執(zhí)行的過程中CPU不要切換到其他線程工作. 這時就需要同步.
如果兩段代碼是同步的, 那么同一時間只能執(zhí)行一段, 在一段代碼沒執(zhí)行結(jié)束之前, 不會執(zhí)行另外一段代碼.
2.同步代碼塊
使用synchronized關(guān)鍵字加上一個鎖對象來定義一段代碼, 這就叫同步代碼塊
多個同步代碼塊如果使用相同的鎖對象, 那么他們就是同步的
3.同步方法
使用synchronized關(guān)鍵字修飾一個方法, 該方法中所有的代碼都是同步的
非靜態(tài)同步函數(shù)的鎖是:this
靜態(tài)的同步函數(shù)的鎖是:字節(jié)碼對象
例:同步代碼塊
例:同步方法
死鎖(必須掌握)?: 在程序里面,有兩個鎖,A線程鎖住第一個,B線程鎖住了第二個,這時如果A再試圖鎖第二個,失敗,因為B已經(jīng)鎖住了,A只能等待.就在這時B試圖鎖第一個,結(jié)果失敗,因為A已經(jīng)鎖住了,B只好等待.就這樣大家一直等下去,誰都不放,天荒地老...
多線程同步的時候, 如果同步代碼嵌套, 使用相同鎖, 就有可能出現(xiàn)死鎖
例:
線程通信:
1.什么時候需要通信
多個線程并發(fā)執(zhí)行時, 在默認情況下CPU是隨機切換線程的如果我們希望他們有規(guī)律的執(zhí)行, 就可以使用通信, 例如每個線程執(zhí)行一次打印
2.怎么通信:
如果希望線程等待, 就調(diào)用wait()
如果希望喚醒等待的線程, 就調(diào)用notify();
這兩個方法必須在同步代碼中執(zhí)行, 并且使用同步鎖對象來調(diào)用
如果多個線程之間通信, 需要使用notifyAll()通知所有線程
線程的五種狀態(tài):
1难述、新建(new):線程對象被創(chuàng)建后就進入了新建狀態(tài)。如:Thread thread = new Thread();
2胁后、就緒狀態(tài)(Runnable):也被稱為“可執(zhí)行狀態(tài)”择同。線程對象被創(chuàng)建后净宵,其他線程調(diào)用了該對象的start()方法裹纳,從而啟動該線程剃氧。如:thread.start(); 處于就緒狀態(tài)的線程隨時可能被CPU調(diào)度執(zhí)行。
3已添、運行狀態(tài)(Running):線程獲取CPU權(quán)限進行執(zhí)行更舞。需要注意的是缆蝉,線程只能從就緒狀態(tài)進入到運行狀態(tài)。
4黍瞧、阻塞狀態(tài)(Blocked):阻塞狀態(tài)是線程因為某種原因放棄CPU使用權(quán)限印颤,暫時停止運行污尉。直到線程進入就緒狀態(tài),才有機會進入運行狀態(tài)某宪。
阻塞的三種情況:?
1)等待阻塞:通過調(diào)用線程的wait()方法兴喂,讓線程等待某工作的完成衣迷。
? 2)同步阻塞:線程在獲取synchronized同步鎖失敽恕(因為鎖被其他線程占用)汗菜,它會進入同步阻塞狀態(tài)陨界。?
3)其他阻塞:通過調(diào)用線程的sleep()或join()或發(fā)出了I/O請求時痛阻,線程會進入到阻塞狀態(tài)阱当。當(dāng)sleep()狀態(tài)超? 時、join()等待線程終止或超時录淡、或者I/O處理完畢時赁咙,線程重新轉(zhuǎn)入就緒狀態(tài)钮莲。
5崔拥、死亡狀態(tài)(Dead):線程執(zhí)行完了或因異常退出了run()方法链瓦,該線程結(jié)束生命周期慈俯。?