進(jìn)程和線程的區(qū)別
進(jìn)程和線程的由來(lái)

進(jìn)程是資源分配的最小單位,線程是CPU調(diào)度的最小單位
所有與進(jìn)程相關(guān)的資源,都被記錄在PCB中
進(jìn)程是搶占處理機(jī)的調(diào)度單位;線程屬于某個(gè)進(jìn)程,共享其資源
線程只有堆棧寄存器、程序計(jì)數(shù)器和TCB(線程控制表)組成
總結(jié)
線程不能看做獨(dú)立應(yīng)用,而進(jìn)程可看做獨(dú)立應(yīng)用
進(jìn)程有獨(dú)立的地址空間,互相不影響,線程只是進(jìn)程的不同執(zhí)行路徑
線程沒(méi)有獨(dú)立的地址空間,多進(jìn)程的程序比多線程的程序健壯
進(jìn)程的切換比線程的切換開(kāi)銷大
Java進(jìn)程和線程的關(guān)系
Java對(duì)操作系統(tǒng)提供的功能進(jìn)行封裝,包括進(jìn)程和線程
運(yùn)行一個(gè)程序會(huì)產(chǎn)生一個(gè)進(jìn)程,進(jìn)程包含至少一個(gè)線程
每個(gè)進(jìn)程對(duì)應(yīng)一個(gè)JVM實(shí)例,多個(gè)線程共享JVM里的堆
Java采用單線程編程模型,程序會(huì)自動(dòng)創(chuàng)建主線程
主線程可以創(chuàng)建子線程,原則上要后于子線程完成執(zhí)行
進(jìn)程間通信
管道:速度慢,容量有限,只有父子進(jìn)程能通訊
FIFO:任何進(jìn)程間都能通訊,但速度慢
消息隊(duì)列:容量受到系統(tǒng)限制,且要注意第一次讀的時(shí)候,要考慮上一次沒(méi)有讀完數(shù)據(jù)的問(wèn)題
信號(hào)量:不能傳遞復(fù)雜消息,只能用來(lái)同步
共享內(nèi)存區(qū):能夠很容易控制容量,速度快,但要保持同步,比如一個(gè)進(jìn)程在寫的時(shí)候,另一個(gè)進(jìn)程要注意讀寫的問(wèn)題,相當(dāng)于線程中的線程安全,當(dāng)然,共享內(nèi)存區(qū)同樣可以用作線程間通訊,不過(guò)沒(méi)這個(gè)必要,線程間本來(lái)就已經(jīng)共享了同一進(jìn)程內(nèi)的一塊內(nèi)存
Thread中的run和start的區(qū)別
調(diào)用start()方法會(huì)創(chuàng)建一個(gè)新的子線程并啟動(dòng)
run()方法只是Thread的一個(gè)普通方法的調(diào)用
Thread和Runnable的關(guān)系
Thread是實(shí)現(xiàn)了Runnable接口的類,使得run支持多線程
因類的單一繼承原則,推薦多使用Runnable接口
public class MyRunnable implements Runnable {
private String name;
public MyRunnable(String name){
this.name = name;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Thread start:" + this.name + ",i=" + i);
}
}
public static void main(String[] args) {
MyRunnable mr1 = new MyRunnable("Runnable1");
MyRunnable mr2 = new MyRunnable("Runnable2");
MyRunnable mr3 = new MyRunnable("Runnable3");
Thread t1 = new Thread(mr1);
Thread t2 = new Thread(mr2);
Thread t3 = new Thread(mr3);
t1.start();
t2.start();
t3.start();
}
}
如何給run()方法傳參
構(gòu)造函數(shù)傳參
成員變量傳參
回調(diào)函數(shù)傳參
如何實(shí)現(xiàn)處理線程的返回值
主線程等待法
使用Thread類的join()阻塞當(dāng)前線程以等待子線程處理完畢
通過(guò)Callable接口實(shí)現(xiàn):通過(guò)FutureTask或者線程池獲取
import java.util.concurrent.*;
/**
* @author lijiayin
*/
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
String value = "test";
System.out.println("Ready to work");
Thread.sleep(5000);
System.out.println("Work finish");
return value;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<MyCallable> futureTask = new FutureTask(new MyCallable());
new Thread(futureTask).start();
if(!futureTask.isDone()){
System.out.println("Work not finish");
}
System.out.println("return value : " + futureTask.get());
ExecutorService executorService = Executors.newCachedThreadPool();
Future<String> future = executorService.submit(new MyCallable());
if(!future.isDone()){
System.out.println("Work not finish");
}
try{
System.out.println("return value : " + future.get());
}catch (Exception e){
e.printStackTrace();
}finally {
executorService.shutdown();
}
}
}
線程的狀態(tài)
新建(New):創(chuàng)建后尚未啟動(dòng)的線程狀態(tài)
-
運(yùn)行(Runnable):包含Running和Ready
無(wú)限期等待(Waiting):不會(huì)被分配CPU執(zhí)行時(shí)間,需要顯式被喚醒
沒(méi)有設(shè)置Timeout參數(shù)的Object.wait()方法
沒(méi)有設(shè)置Timeout參數(shù)的Thread.join()方法
LockSupport.park()方法
-
限期等待(Timed Waiting):在一定時(shí)間后會(huì)由系統(tǒng)自動(dòng)喚醒
Thread.sleep()方法
設(shè)置了Timeout參數(shù)的Object.wait()方法
設(shè)置了Timeout參數(shù)的Thread.join()方法
LockSupport.parkNanos()方法
LockSupport.parkUntil()方法
阻塞(Blocked):等待獲取排它鎖
結(jié)束(Terminated):已終止線程的狀態(tài),線程已經(jīng)結(jié)束執(zhí)行
sleep和wait的區(qū)別
基本的差別
sleep是Thread類的方法,wait是Object類中定義的方法
sleep()方法可以在任何地方使用
wait()方法只能在synchronized方法或者synchronized塊中使用
最主要的本質(zhì)區(qū)別
Thread.sleep只會(huì)讓出CPU,不會(huì)導(dǎo)致鎖行為的改變
Object.wait不僅讓出CPU,還會(huì)釋放已經(jīng)占有的同步資源鎖
notify和notifyAll的區(qū)別
兩個(gè)概念
鎖池EntryList:假設(shè)線程A已經(jīng)擁有了某個(gè)對(duì)象(不是類)的鎖,而其它線程B、C想要調(diào)用這個(gè)對(duì)象的synchronized方法(或者塊),由于B、C線程在進(jìn)入對(duì)象的synchronized方法(或者塊)之前必須獲得該對(duì)象鎖的擁有權(quán),而恰巧該對(duì)象的鎖目前正被線程A所占用,此時(shí)B、C線程就會(huì)被阻塞,進(jìn)入一個(gè)地方去等待鎖的釋放,這個(gè)地方便是該對(duì)象的鎖池。
等待池WaitSet:假設(shè)線程A調(diào)用了某個(gè)對(duì)象的wait()方法,線程A就會(huì)釋放該對(duì)象的鎖,同時(shí)線程A就進(jìn)入到了該對(duì)象的等待池中,進(jìn)入到等待池中的線程不會(huì)去競(jìng)爭(zhēng)該對(duì)象的鎖。
結(jié)論
notifyAll會(huì)讓所有處于等待池的線程全部進(jìn)入鎖池去競(jìng)爭(zhēng)獲取鎖的機(jī)會(huì)。
notify只會(huì)隨機(jī)選取一個(gè)處于等待池中的線程進(jìn)入鎖池去競(jìng)爭(zhēng)獲取鎖的機(jī)會(huì)。
yield
概念
當(dāng)調(diào)用Thread.yield()函數(shù)時(shí),會(huì)給線程調(diào)度器一個(gè)當(dāng)前線程愿意讓出CPU使用的暗示,但是線程調(diào)度器可能會(huì)忽略這個(gè)暗示。
對(duì)鎖行為沒(méi)有影響。
interrupt函數(shù)
通知線程應(yīng)該中斷了
如果線程處于被阻塞狀態(tài),那么線程將立即退出被阻塞狀態(tài),并拋出一個(gè)InterruptedException異常
如果線程處于正常活動(dòng)狀態(tài),那么會(huì)將該線程的中斷標(biāo)志設(shè)置為true。被設(shè)置中斷標(biāo)志的線程將繼續(xù)正常運(yùn)行,不受影響。
需要被調(diào)用的線程配合中斷
在正常運(yùn)行任務(wù)時(shí),經(jīng)常檢查本線程的中斷標(biāo)志位,如果被設(shè)置了中斷就自行停止線程。
如果線程處于正?;顒?dòng)狀態(tài),那么會(huì)將該線程的中斷標(biāo)志設(shè)置為true。被設(shè)置中斷標(biāo)志的線程將繼續(xù)正常運(yùn)行,不受影響。
