『來源:HollisChuang』
1、進程和線程的區別
??進程是具有一定獨立功能的程序關于某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。每一個進程都有一個自己的地址空間。進程具有一定的獨立功能。
??線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。線程在程序中是獨立的并發的執行流。
??線程自己不擁有系統資源,它與父進程的其他線程共享該進程所擁有的全部資源,線程只擁有一點在運行中必不可少的資源,比如:自己的堆棧、自己的程序計數器和自己的局部變量。
??一個線程可以創建和撤銷另一個線程;同一個進程中的多個線程之間可以并發執行。線程的執行時搶占式的,也就意味著當前運行的線程在任何時候都有可能被掛起,以便另外一個線程可以運行。
?
區別:
??① 一個程序至少有一個進程,一個進程至少有一個線程
??② 內存共享:進程在執行過程中擁有獨立的內存單元(一個進程崩潰后,在保護模式下不會對其它進程產生影響);
??而多個線程共享進程提供的內存(擁有自己的私有棧空間只是作為運行需要的極少內存),從而極大地提高了程序的運行效率,但一個線程死掉就等于整個進程死掉。所以多進程的程序要比多線程的程序健壯
??③ 因為線程的劃分尺度小于進程,使得多線程程序的并發行高。
??④ 執行過程:進程獨立執行;線程不能夠獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。
??⑤ 從邏輯角度來看,多線程的意義在于一個應用程序中,有多個執行部分可以同時執行。
??但操作系統并沒有將多個線程看做多個獨立的應用,來實現進程的調度和管理以及資源分配。這就是進程和線程的重要區別。
參考鏈接
https://blog.csdn.net/mxsgoden/article/details/8821936
??
2、并行和并發的區別和聯系
??并行:是指在同一時刻,有多條指令在多個處理器上同時執行。
??并發:是指在同一時刻只能有一條指令執行,但多個進程指令被快速輪換執行,使得在宏觀上具有多個進程同時執行的效果。
??
3、同步和異步
??同步:可以理解為在執行完一個函數或方法之后,一直等待系統返回值或消息,這時程序是出于阻塞的,只有接收到返回的值或消息后才往下執行其他的命令。
??異步:執行完函數或方法后,不必阻塞性地等待返回值或消息,只需要向系統委托一個異步過程,那么當系統接收到返回值或消息時,系統會自動觸發委托的異步過程,通過狀態、通知和回調來通知調用者,從而完成一個完整的流程。
??同步在一定程度上可以看做是單線程,這個線程請求一個方法后就待這個方法給他回復,否則他不往下執行(死心眼)。
??異步在一定程度上可以看做是多線程的,請求一個方法后,就不管了,繼續執行其他的方法,等有返回值以后,再回來執行程序
??
4、多線程的實現方式,有什么區別
實現方式:
① 繼承Thread
類
??繼承Thread
類,重寫run()
方法,實例化線程類,調用start()
方法啟動線程。
??
??
② 實現Runnable
接口
??實現Runnable
接口并重寫run()
方法,創建Runnable
實例,并以此實例作為Thread
類的target
參數創建Thread
對象,調用Thread
對象的start()
啟動線程
??
③ 使用Callable
接口和Future
來創建線程
??
??實現Callable
接口,并實現call()
方法,并創建Callable
實例,然后使用FutureTask
對象來包裝Callable
實例,使用FutureTask
對象作為Thread
的target
來創建并啟動線程
??
區別:
??Runnable
接口和Callable
接口的方式基本相同(實現Runnable
接口和Callable
接口僅僅是創建了一個任務,但是仍然需要Thread
類來創建線程并啟動),他倆唯一區別只是Callable
接口實現方法有返回值,并且也可以聲明拋出異常而已,可以歸為一類。
??
1、繼承Thread
實現線程
??① 已經繼承了Thread
類,不能繼承其他類
??② 獲取當前線程,可以直接使用this
來獲得
??
2、實現Runnable
接口、Callable
接口創建線程
??①實現的是接口,還可以繼承其他類
??② 多個線程可以共享同一個target
對象,適合多個相同的線程來處理同一份資源的情況
??③ 獲取當前線程必須用Thread.currentThread()
方法來獲得
http://www.liuzk.com/183.html
??
5、什么叫守護線程
??在Java中有兩類線程:User Thread(用戶線程)、Daemon Thread(守護線程) 。
??守護線程, 是指在程序運行的時候在后臺提供一種通用服務的線程, 比如垃圾回收線程就是一個很稱職的守護者。
??并且這種線程并不屬于程序中不可或缺的部分。因此只要當前JVM實例中尚存在任何一個非守護線程沒有結束,守護線程就全部工作;只有當最后一個非守護線程結束時,守護線程隨著JVM一同結束工作。
??可以通過調用線程的setDaemon()
方法,傳入參數true,將一個用戶線程設置為一個守護線程
??
這里有幾點需要注意:
??(1) thread.setDaemon()
必須在thread.start()
之前設置,否則會跑出一個IllegalThreadStateException
異常。你不能把正在運行的常規線程設置為守護線程。
??(2) 在Daemon線程中產生的新線程也是Daemon的。
??(3) 不要認為所有的應用都可以分配給Daemon來進行服務,比如讀寫操作或者計算邏輯。 因為你不可能知道在所有的User完成之前,Daemon是否已經完成了預期的服務任務。一旦User退出了,可能大量數據還沒有來得及讀入或寫出,計算任務也可能多次運行結果不一樣。這對程序是毀滅性的。
??
6、如何停止一個線程?
??① 設置一個標志位 需要用volatile
來修飾,保證線程讀取時標志位是最新數據
??② 在sleep
狀態下使用interrupt()
方法,程序拋出InterruptedException
,捕捉這個異常來結束程序。但仍要調用Thread.currentThread().interrupt()
恢復中斷,讓線程退出。
??
7、什么是線程安全?
??線程安全就是多線程訪問同一代碼,不會產生不確定的結果。
如何保證線程安全
對非安全的代碼進行加鎖控制;
使用線程安全的類;
多線程并發情況下,線程共享的變量改為方法級的局部變量。
https://blog.csdn.net/suifeng3051/article/details/52164267
??
8、synchronized 和 lock的區別
主要相同點:
??Lock能完成synchronized所實現的所有功能
主要不同點:
??Lock有比synchronized更精確的線程語義和更好的性能。
??Lock的鎖定是通過代碼實現的,而synchronized是在JVM層面上實現的,synchronized會自動釋放鎖,而Lock一定要求程序員手工釋放,并且必須在finally從句中釋放。
??Lock還有更強大的功能,例如,它的tryLock方法可以非阻塞方式去拿鎖。
??Lock鎖的范圍有局限性,塊范圍,而synchronized可以鎖住塊、對象、類。
??
9、當一個線程進入一個對象的一個synchronized方法后,其它線程是否可進入此對象的其它方法?
現在分兩種情況來討論:
??1.當前線程調用的是synchronized普通方法(相對于static方法);
??2.當前線程調用的是synchronized static方法。
1.當前線程調用的是synchronized普通方法(相對于static方法)時,其它線程是否可進入此對象的其它方法:
1)其它方法是加了synchronized的普通方法,不能;
2)其它方法是沒加synchronized的普通方法,能;
3)其它方法是synchronized的static方法,能;
4)其它方法是沒加synchronized的static方法,能。
5)如果這個方法內部調用了wait,則可以進入其他synchronized方法。
(因為當前線程執行同步代碼塊或同步方法時,程序執行了同步監視器對象的wait()方法,則當前線程暫停,并釋放同步器)
2.當前線程調用的是synchronized static方法,其它線程是否可進入此對象的其它方法:
1)其它方法是加了synchronized的普通方法,能;
2)其它方法是沒加synchronized的普通方法,能;
3)其它方法是synchronized的static方法,不能;
4)其它方法中有synchronized(xxx.class)的,不能;
5)其它方法是沒加synchronized的static方法,能。
所謂的synchronized(xxx.class)就是同步代碼塊:
public void method5(){
synchronized(xxx.class){
System.out.println("this is a synchronized static method——method5.");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
參考鏈接:java線程之——synchronized的注意細節
??
10、啟動一個線程是用run()還是start()?
??啟動一個線程是使用star(),啟動線程后,系統會把該線程的run()方法當成線程執行體來處理。
??如果使用的是run()方法,則run()方法會被立即執行,而且在run()方法返回之前其他線程無法并發執行。
??因此如果直接調用線程對象的run()方法,系統會把線程對象當成一個普通對象,而run()方法也是一個普通方法,而不是線程體。
??
11、wait和sleep的區別
??sleep()方法是Thread類中方法,而wait()方法是Object類中的方法。
??sleep()方法導致了程序暫停執行指定的時間,讓出cpu該其他線程,但是它的監控狀態依然保持者,當指定的時間到了又會自動恢復運行狀態。在調用sleep()方法的過程中,線程不會釋放對象鎖。
??而當調用wait()方法的時候,線程會放棄對象鎖,進入等待此對象的等待鎖定池,只有針對此對象調用notify()方法后本線程才進入對象鎖定池準備。
??
12、notify()和notifyAll()的區別
notify():
??喚醒在次同步監視器上等待的單個線程,如果所有線程都在此同步監視器上等待,則會選擇喚醒其中一個線程。
??選擇是任意性的。只有當前線程放棄對該同步監視器的鎖定后(使用wait()方法),才可以執行被喚醒的線程
notifyAll():
??喚醒在此同步監視器上等待的所有線程。只有當前線程放棄該同步監視器的鎖定后,才可以執行被喚醒的線程。
??