多線程

image.png

1. 使用多線程有什么好處?

多線程有多種好處仗扬,如下所示:

  • 即使程序的一部分被阻塞症概,也允許程序繼續(xù)運(yùn)行。
  • 與使用多個(gè)進(jìn)程的傳統(tǒng)并行程序相比早芭,提高了性能彼城。
  • 允許編寫利用最大 CPU 時(shí)間的有效程序
  • 提高復(fù)雜應(yīng)用程序或程序的響應(yīng)能力。
  • 增加 CPU 資源的使用并降低維護(hù)成本。
  • 節(jié)省時(shí)間和并行任務(wù)募壕。
  • 如果在單個(gè)線程中發(fā)生異常调炬,它不會(huì)影響其他線程,因?yàn)榫€程是獨(dú)立的舱馅。
  • 與同時(shí)執(zhí)行多個(gè)進(jìn)程相比缰泡,資源密集型更少。

2. Java中的線程是什么代嗤?

線程基本上是可以由調(diào)度程序獨(dú)立管理的輕量級(jí)和最小的處理單元棘钞。線程被稱為進(jìn)程的一部分,它只是讓程序與進(jìn)程的其他部分或線程同時(shí)有效地執(zhí)行干毅。使用線程宜猜,可以以最簡(jiǎn)單的方式執(zhí)行復(fù)雜的任務(wù)。它被認(rèn)為是利用機(jī)器中可用的多個(gè) CPU 的最簡(jiǎn)單方法硝逢。它們共享公共地址空間并且彼此獨(dú)立姨拥。

3、Java實(shí)現(xiàn)線程的兩種方式是什么渠鸽?

在java中實(shí)現(xiàn)線程基本上有兩種方法叫乌,如下所示:

  • 擴(kuò)展線程

例子:

class MultithreadingDemo extends Thread 
{   
  public void run() 
 {   
     System.out.println("My thread is in running state.");    
 } 
  public static void main(String args[]) 
 {   
    MultithreadingDemoobj=new MultithreadingDemo();  
        obj.start();  
  }  
} 

輸出:

My thread is in running state.
  • 在 Java 中實(shí)現(xiàn)Runnable接口

示例

class MultithreadingDemo implements Runnable 
{  
   public void run() 
 {  
      System.out.println("My thread is in running state.");  
  }  
    public static void main(String args[]) 
 {  
      MultithreadingDemo obj=new MultithreadingDemo();   
      Threadtobj =new Thread(obj);       tobj.start();  
 }   
} 

輸出:

My thread is in running state. 

4、線程和進(jìn)程有什么區(qū)別拱绑?

線程:它只是指特定進(jìn)程的最小單元。它具有同時(shí)執(zhí)行程序的不同部分(稱為線程)的能力丽蝎。

進(jìn)程:它只是指正在執(zhí)行的程序猎拨,即活動(dòng)程序⊥雷瑁可以使用 PCB(過程控制塊)處理過程红省。

image.png

過程
它是進(jìn)程子單元的子集。 它是一個(gè)包含多個(gè)線程的正在執(zhí)行的程序国觉。
在這種情況下吧恃,線程間通信更快、更便宜麻诀、更容易痕寓、更高效,因?yàn)榫€程共享它們所屬進(jìn)程的相同內(nèi)存地址蝇闭。 在這種情況下呻率,進(jìn)程間通信更慢、更昂貴呻引、更復(fù)雜礼仗,因?yàn)槊總€(gè)進(jìn)程都有不同的內(nèi)存空間或地址。
這些更容易創(chuàng)建、輕量級(jí)并且開銷更少元践。 這些很難創(chuàng)建韭脊,重量級(jí),并且有更多的開銷单旁。
它需要更少的時(shí)間來創(chuàng)建沪羔、終止和上下文切換。 它需要更多的時(shí)間來創(chuàng)建慎恒、終止和上下文切換任内。
具有多個(gè)線程的進(jìn)程使用較少的資源。 沒有線程的進(jìn)程使用更多資源融柬。
線程是進(jìn)程的一部分死嗦,因此它們相互依賴,但每個(gè)線程獨(dú)立執(zhí)行粒氧。 進(jìn)程相互獨(dú)立越除。
需要在線程中進(jìn)行同步以避免意外情況或問題。 每個(gè)進(jìn)程都不需要同步外盯。
他們彼此共享數(shù)據(jù)和信息摘盆。 他們不相互共享數(shù)據(jù)。

5. 類鎖和對(duì)象鎖有什么區(qū)別饱苟?

類鎖:在java中孩擂,每個(gè)類都有一個(gè)唯一的鎖,通常稱為類級(jí)鎖箱熬。這些鎖是使用關(guān)鍵字“靜態(tài)同步”實(shí)現(xiàn)的类垦,可用于使靜態(tài)數(shù)據(jù)線程安全。它通常在想要防止多個(gè)線程進(jìn)入同步塊時(shí)使用城须。

例子:

public class ClassLevelLockExample  
{    
  public void classLevelLockMethod()  
 {       
     synchronized (ClassLevelLockExample.class)  
       {         
            //DO your stuff here       
       }    
 } 
} 

對(duì)象鎖:在java中蚤认,每個(gè)對(duì)象都有一個(gè)唯一的鎖,通常稱為對(duì)象級(jí)鎖糕伐。這些鎖是使用關(guān)鍵字“synchronized”實(shí)現(xiàn)的砰琢,可用于保護(hù)非靜態(tài)數(shù)據(jù)。它通常在想要同步非靜態(tài)方法或塊時(shí)使用良瞧,以便只有線程能夠在給定的類實(shí)例上執(zhí)行代碼塊陪汽。

示例 :

public class ObjectLevelLockExample  
{    
  public void objectLevelLockMethod()  
 {   
     synchronized (this)  
       {     
            //DO your stuff here   
       } 
 }
} 

6、User線程和Daemon線程有什么區(qū)別褥蚯?

用戶和守護(hù)進(jìn)程基本上是 Java 中使用“線程類”的兩種類型的線程掩缓。

用戶線程(非守護(hù)線程):在 Java 中,用戶線程具有特定的生命周期遵岩,其生命周期獨(dú)立于任何其他線程你辣。JVM(Java 虛擬機(jī))在終止之前等待任何用戶線程完成其任務(wù)巡通。當(dāng)用戶線程完成時(shí),JVM 會(huì)終止整個(gè)程序以及相關(guān)的守護(hù)線程舍哄。

守護(hù)線程:在Java中宴凉,守護(hù)線程基本上被稱為服務(wù)提供者,為用戶線程提供服務(wù)和支持表悬。守護(hù)線程的線程類中基本上有兩種可用的方法:setDaemon() 和 isDaemon()弥锄。

用戶線程與守護(hù)線程

用戶線程 守護(hù)線程
JVM 在終止前等待用戶線程完成其任務(wù)。 JVM 在終止前不會(huì)等待守護(hù)線程完成其任務(wù)蟆沫。
這些線程通常由用戶創(chuàng)建籽暇,用于并發(fā)執(zhí)行任務(wù)。 這些線程通常由 JVM 創(chuàng)建饭庞。
它們用于應(yīng)用程序的關(guān)鍵任務(wù)或核心工作戒悠。 它們不用于任何關(guān)鍵任務(wù),而是用于執(zhí)行一些輔助任務(wù)舟山。
這些線程被稱為高優(yōu)先級(jí)任務(wù)绸狐,因此需要在前臺(tái)運(yùn)行。 這些線程被稱為低優(yōu)先級(jí)線程累盗,因此特別需要支持后臺(tái)任務(wù)寒矿,如垃圾收集、釋放未使用對(duì)象的內(nèi)存等若债。

7.我們?nèi)绾蝿?chuàng)建守護(hù)線程符相?

我們可以使用線程類setDaemon(true)在 java 中創(chuàng)建守護(hù)線程。它用于將當(dāng)前線程標(biāo)記為守護(hù)線程或用戶線程蠢琳。isDaemon()方法一般用于檢查當(dāng)前線程是否為守護(hù)進(jìn)程啊终。如果線程是守護(hù)進(jìn)程,它將返回 true挪凑,否則返回 false孕索。
示例
**說明 setDaemon() 和 isDaemon() 方法使用的程序逛艰。 **

public class DaemonThread extends Thread 
{ 
   public DaemonThread(String name){ 
       super(name); 
   } 
   public void run() 
   {  
       // Checking whether the thread is Daemon or not 
       if(Thread.currentThread().isDaemon()) 
       {  
           System.out.println(getName() + " is Daemon thread");  
       }    
       else 
       {  
           System.out.println(getName() + " is User thread");  
       }  
   }   
   public static void main(String[] args) 
   {  
       DaemonThread t1 = new DaemonThread("t1"); 
       DaemonThread t2 = new DaemonThread("t2"); 
       DaemonThread t3 = new DaemonThread("t3");  
       // Setting user thread t1 to Daemon 
       t1.setDaemon(true);       
       // starting first 2 threads  
       t1.start();  
       t2.start();   
       // Setting user thread t3 to Daemon 
       t3.setDaemon(true);  
       t3.start();         
   }  
} 

輸出:

t1 is Daemon thread 
t3 is Daemon thread 
t2 is User thread 

但是只能在start() 方法之前調(diào)用 setDaemon()方法躏碳,否則肯定會(huì)拋出 IllegalThreadStateException,如下所示:

public class DaemonThread extends Thread 
{ 
   public void run() 
   { 
       System.out.println("Thread name: " + Thread.currentThread().getName()); 
       System.out.println("Check if its DaemonThread: "  
                       + Thread.currentThread().isDaemon()); 
   } 
   public static void main(String[] args) 
   { 
       DaemonThread t1 = new DaemonThread(); 
       DaemonThread t2 = new DaemonThread(); 
       t1.start();         
       // Exception as the thread is already started 
       t1.setDaemon(true); 
       t2.start(); 
   } 
} 

輸出:

Thread name: Thread-0 
Check if its DaemonThread: false 

8. wait() 和 sleep() 方法是什么散怖?

wait():顧名思義菇绵,它是一種非靜態(tài)方法,它會(huì)導(dǎo)致當(dāng)前線程等待并進(jìn)入睡眠狀態(tài)镇眷,直到其他一些線程為對(duì)象的監(jiān)視器(鎖)調(diào)用 notify() 或 notifyAll() 方法咬最。它只是釋放鎖,主要用于線程間通信欠动。它在對(duì)象類中定義永乌,并且只能從同步上下文中調(diào)用惑申。

synchronized(monitor) 
{ 
monitor.wait();       Here Lock Is Released by Current Thread  
} 

sleep():顧名思義鸣个,它是一種靜態(tài)方法限次,可以暫拖穹或停止當(dāng)前線程的執(zhí)行一段時(shí)間抛杨。它在等待時(shí)不會(huì)釋放鎖掸驱,主要用于在執(zhí)行時(shí)引入暫停端礼。它在線程類中定義刘莹,無需從同步上下文中調(diào)用暇藏。

synchronized(monitor) 
{ 
Thread.sleep(1000);     Here Lock Is Held by The Current Thread 
//after 1000 milliseconds, the current thread will wake up, or after we call that is interrupt() method 
} 

9. notify() 和 notifyAll() 有什么區(qū)別橄抹?

notify():它發(fā)送一個(gè)通知并且只喚醒一個(gè)線程而不是多個(gè)線程在對(duì)象的監(jiān)視器上等待靴迫。

image.png

notifyAll():它發(fā)送通知并喚醒所有線程并允許它們競(jìng)爭(zhēng)對(duì)象的監(jiān)視器而不是單個(gè)線程。

image.png

10. 為什么 Object 類中存在 wait()楼誓、notify() 和 notifyAll() 方法玉锌?

image.png

我們知道每個(gè)對(duì)象都有一個(gè)監(jiān)視器,它允許線程持有對(duì)象上的鎖慌随。但是線程類不包含任何監(jiān)視器芬沉。線程通常通過調(diào)用對(duì)象的wait()方法等待對(duì)象的監(jiān)視器(鎖),并使用notify()或notifyAll()方法通知正在等待同一鎖的其他線程阁猜。因此丸逸,這三個(gè)方法僅在對(duì)象上調(diào)用,并允許所有線程與在該對(duì)象上創(chuàng)建的每個(gè)線程進(jìn)行通信剃袍。

11.什么是Runnable和Callable接口黄刚?寫出它們之間的區(qū)別。

這兩個(gè)接口一般都用于封裝需要由另一個(gè)線程執(zhí)行的任務(wù)民效。但是它們之間有一些區(qū)別憔维,如下所示:

運(yùn)行接口:這個(gè)接口基本上從一開始就在 Java 中可用。它僅用于在并發(fā)線程上執(zhí)行代碼畏邢。
可調(diào)用接口:這個(gè)接口基本上是作為并發(fā)包的一部分引入的新接口业扒。它解決了可運(yùn)行接口的限制以及一些重大變化,如泛型舒萎、枚舉程储、靜態(tài)導(dǎo)入、變量參數(shù)方法等臂寝。它使用泛型來定義對(duì)象的返回類型章鲤。

public interface Runnable  
{   
  public abstract void run(); 
}  
public interface Callable<V>  
{    
V call() throws Exception;  
} 

可運(yùn)行接口與可調(diào)用接口

可運(yùn)行接口 可調(diào)用接口
它不返回任何結(jié)果,因此不能拋出檢查異常咆贬。 它返回一個(gè)結(jié)果败徊,因此可以拋出異常。
它不能傳遞給 invokeAll 方法掏缎。 它可以傳遞給 invokeAll 方法皱蹦。
它是在 JDK 1.0 中引入的煤杀。 它是在 JDK 5.0 中引入的,因此在 Java 5 之前不能使用它沪哺。
它只是屬于 Java.lang怜珍。 它只是屬于 java.util.concurrent。
它使用 run() 方法來定義任務(wù)凤粗。 它使用 call() 方法來定義任務(wù)酥泛。
要使用此接口,需要重寫 run() 方法嫌拣。 要使用此接口柔袁,需要重寫 call() 方法。

12异逐、Thread類的start()和run()方法是什么捶索?

start():簡(jiǎn)單來說,start() 方法用于啟動(dòng)或開始執(zhí)行新創(chuàng)建的線程灰瞻。當(dāng)調(diào)用 start() 方法時(shí)腥例,會(huì)創(chuàng)建一個(gè)新線程,并且這個(gè)新創(chuàng)建的線程會(huì)執(zhí)行保存在 run() 方法中的任務(wù)酝润。一個(gè)人只能調(diào)用一次 start() 方法燎竖。

run():簡(jiǎn)單來說,run() 方法用于啟動(dòng)或開始執(zhí)行同一個(gè)線程要销。當(dāng)調(diào)用 run() 方法時(shí)构回,不會(huì)像 start() 方法那樣創(chuàng)建新線程。該方法由當(dāng)前線程執(zhí)行疏咐∠说В可以多次調(diào)用 run() 方法。

13.解釋線程池浑塞?

線程池只是啟動(dòng)時(shí)預(yù)初始化或工作線程的集合借跪,可用于執(zhí)行任務(wù)并在完成時(shí)放回池中。它被稱為池線程酌壕,其中創(chuàng)建了一組固定大小的線程掏愁。通過減少應(yīng)用程序線程的數(shù)量并管理它們的生命周期,可以使用線程池來緩解性能問題仅孩。使用線程托猩,可以提高性能并實(shí)現(xiàn)更好的系統(tǒng)穩(wěn)定性印蓖。為了創(chuàng)建線程池辽慕,java.util.concurrent.Executors 類通常提供工廠方法。

14. join() 方法的目的是什么赦肃?

join()方法通常用于暫停當(dāng)前線程的執(zhí)行溅蛉,除非并且直到調(diào)用 join 的指定線程死亡或完成公浪。要停止一個(gè)線程運(yùn)行直到另一個(gè)線程結(jié)束,可以使用此方法船侧。它將一個(gè)線程執(zhí)行的開始連接到另一個(gè)線程執(zhí)行的結(jié)束欠气。它被認(rèn)為是線程類的最終方法。

15. 垃圾回收是什么意思镜撩?

垃圾回收基本上是一個(gè)自動(dòng)管理內(nèi)存的過程预柒。它使用了幾種 GC 算法,其中流行的一種包括 Mark 和 Sweep袁梗。該過程包括三個(gè)階段宜鸯,即標(biāo)記、刪除和壓縮/復(fù)制遮怜。簡(jiǎn)單來說淋袖,垃圾收集器找到程序不再需要的對(duì)象,然后刪除或移除這些未使用的對(duì)象以釋放內(nèi)存空間锯梁。

16. 解釋死鎖的含義以及何時(shí)會(huì)發(fā)生即碗?

死鎖,顧名思義陌凳,就是多個(gè)線程永遠(yuǎn)被阻塞的情況剥懒。它通常發(fā)生在多個(gè)線程持有不同資源的鎖并等待其他資源完成其任務(wù)時(shí)。

上圖顯示了兩個(gè)線程被永遠(yuǎn)阻塞的死鎖情況合敦。線程 1 持有對(duì)象 1 但需要對(duì)象 2 才能完成處理蕊肥,而線程 2 持有對(duì)象 2 但首先需要對(duì)象 1。在這種情況下蛤肌,它們都將永遠(yuǎn)保持鎖定并且永遠(yuǎn)不會(huì)完成任務(wù)壁却。

17.解釋Java中的volatile變量?

volatile 變量基本上是一個(gè)關(guān)鍵字裸准,用于確保和解決多線程編程中變量更改的可見性展东。此關(guān)鍵字不能與類和方法一起使用,而是可以與變量一起使用炒俱。它只是用于實(shí)現(xiàn)線程安全盐肃。如果將任何變量標(biāo)記為易失性,那么所有線程都可以直接從主存而不是 CPU 緩存中讀取其值权悟,以便每個(gè)線程都可以獲取變量的更新值砸王。

18.線程之間如何通信?

線程可以使用三種方法進(jìn)行通信峦阁,即wait()谦铃、notify() 和notifyAll()。

19榔昔、兩個(gè)線程可以同時(shí)執(zhí)行兩種方法(靜態(tài)和非靜態(tài))嗎驹闰?

對(duì)的瘪菌,這是可能的。如果兩個(gè)線程都獲得了不同對(duì)象的鎖嘹朗,那么它們可以同時(shí)執(zhí)行而不會(huì)出現(xiàn)任何問題师妙。

20. finalize() 方法的目的是什么?

Finalize() 方法基本上是 Object 類的一種方法屹培,專門用于在垃圾回收之前對(duì)非托管資源執(zhí)行清理操作默穴。它根本不打算被稱為普通方法。完成 finalize() 方法后褪秀,對(duì)象會(huì)自動(dòng)銷毀壁顶。

面向有經(jīng)驗(yàn)的 Java 中的多線程面試問題

21.什么是同步過程?為什么要使用它溜歪?

同步基本上是 java 中的一個(gè)過程若专,它啟用了一種簡(jiǎn)單的策略來避免線程干擾和內(nèi)存一致性錯(cuò)誤。此過程確保當(dāng)一個(gè)線程嘗試訪問共享資源時(shí)蝴猪,該資源一次只被一個(gè)線程使用调衰。它可以通過以下三種不同的方式實(shí)現(xiàn):

  • 通過同步方法
  • 通過同步塊
  • 通過靜態(tài)同步

語法:

synchronized (object) 
{        
   //statement to be synchronized 
} 

22. 什么是同步方法和同步塊?應(yīng)該首選哪一個(gè)自阱?

同步方法:在此方法中嚎莉,線程在進(jìn)入同步方法時(shí)獲取對(duì)象上的鎖,并在離開該方法時(shí)正撑嫱悖或通過拋出異常釋放鎖趋箩。除非當(dāng)前線程完成執(zhí)行并釋放鎖,否則其他線程不能使用整個(gè)方法加派。當(dāng)想要鎖定特定方法的全部功能時(shí)叫确,可以使用它。

Synchronized Block:在該方法中芍锦,線程在synchronized關(guān)鍵字后面的括號(hào)內(nèi)的對(duì)象上獲取鎖竹勉,并在離開塊時(shí)釋放鎖。除非同步塊存在娄琉,否則沒有其他線程可以獲取鎖定對(duì)象上的鎖次乓。當(dāng)一個(gè)人想要保持程序的其他部分可供其他線程訪問時(shí),可以使用它孽水。

同步塊應(yīng)該更受青睞票腰,因?yàn)樗梢蕴岣咛囟ǔ绦虻男阅堋K绘i定程序的某個(gè)部分(關(guān)鍵部分)而不是整個(gè)方法女气,因此導(dǎo)致爭(zhēng)用較少杏慰。

23. 什么是線程饑餓?

線程饑餓基本上是一種情況或條件,即線程無法定期訪問共享資源逃默,因此無法繼續(xù)或取得進(jìn)展。這是因?yàn)槠渌€程優(yōu)先級(jí)高簇搅,占用資源時(shí)間過長(zhǎng)完域。這通常發(fā)生在沒有獲得 CPU 以繼續(xù)執(zhí)行的低優(yōu)先級(jí)線程上。


image.png

24. 什么是活鎖瘩将?當(dāng)它發(fā)生時(shí)會(huì)發(fā)生什么吟税?

與死鎖類似,活鎖也是另一個(gè)并發(fā)問題姿现。在這種情況下肠仪,線程的狀態(tài)在彼此之間發(fā)生變化而沒有任何進(jìn)展。線程不會(huì)被阻塞备典,但由于資源不可用而停止執(zhí)行异旧。

25.什么是阻塞隊(duì)列?

BlockingQueue 基本上代表了一個(gè)線程安全的隊(duì)列提佣。生產(chǎn)者線程使用 put() 方法將資源/元素插入隊(duì)列吮蛹,除非它已滿,而消費(fèi)者線程使用 take() 方法從隊(duì)列中獲取資源拌屏,直到它變空潮针。但是如果一個(gè)線程試圖從一個(gè)空隊(duì)列中出隊(duì),那么一個(gè)特定的線程將被阻塞倚喂,直到某個(gè)其他線程將一個(gè)項(xiàng)目插入隊(duì)列,或者如果一個(gè)線程試圖將一個(gè)項(xiàng)目插入一個(gè)已經(jīng)滿的隊(duì)列端圈,那么一個(gè)特定的線程將被阻塞焦读,直到一些線程從隊(duì)列中取出一個(gè)項(xiàng)目。

image.png

示例:

package org.arpit.java2blog; 

import java.util.concurrent.ArrayBlockingQueue; 
import java.util.concurrent.BlockingQueue; 

public class BlockingQueuePCExample { 

   public static void main(String[] args) { 

       BlockingQueue<String> queue=new ArrayBlockingQueue<>(5); 
       Producer producer=new Producer(queue); 
       Consumer consumer=new Consumer(queue); 
       Thread producerThread = new Thread(producer); 
       Thread consumerThread = new Thread(consumer); 

       producerThread.start(); 
       consumerThread.start(); 

   } 

   static class Producer implements Runnable { 

       BlockingQueue<String> queue=null; 

       public Producer(BlockingQueue queue) { 
           super(); 
           this.queue = queue; 
       } 

       @Override 
       public void run() { 

               try { 
                   System.out.println("Producing element 1"); 
                   queue.put("Element 1"); 
                   Thread.sleep(1000); 
                   System.out.println("Producing element 2"); 
                   queue.put("Element 2"); 
                   Thread.sleep(1000); 
                   System.out.println("Producing element 3"); 
                   queue.put("Element 3"); 
               } catch (InterruptedException e) { 

                   e.printStackTrace(); 
               } 
       } 
   } 

   static class Consumer implements Runnable { 

       BlockingQueue<String> queue=null; 

       public Consumer(BlockingQueue queue) { 
           super(); 
           this.queue = queue; 
       } 

       @Override 
       public void run() { 

           while(true) 
           { 
               try { 
                   System.out.println("Consumed "+queue.take()); 
               } catch (InterruptedException e) { 
                   e.printStackTrace(); 
               } 
           } 
       } 

   } 
} 

輸出

Producing element 1 
Consumed Element 1 
Producing element 2 
Consumed Element 2 
Producing element 3 
Consumed Element 3

26. 一個(gè)線程可以啟動(dòng)兩次嗎舱权?

不吨灭,一旦線程啟動(dòng)并完成其執(zhí)行,就根本不可能重新啟動(dòng)線程刑巧。線程只運(yùn)行一次喧兄,如果您嘗試第二次運(yùn)行它,那么它將拋出運(yùn)行時(shí)異常啊楚,即 java.lang.IllegalThreadStateException吠冤。

示例

public class TestThreadTwice1 extends Thread{   
public void run(){   
System.out.println(" thread is executing now........");   
}   
public static void main(String args[]){   
TestThreadTwice1 t1=new TestThreadTwice1();   
t1.start();   
t1.start();   
}   
}   

輸出:

thread is executing now........ 
Exception in thread "main" java.lang.IllegalThreadStateException  

27. 解釋上下文切換。

上下文切換基本上是多線程的一個(gè)重要特性恭理。它被稱為 CPU 從一個(gè)線程或進(jìn)程切換到另一個(gè)線程或進(jìn)程拯辙。它允許多個(gè)進(jìn)程共享同一個(gè) CPU。在上下文切換中,存儲(chǔ)線程或進(jìn)程的狀態(tài)涯保,以便稍后可以在需要時(shí)恢復(fù)線程的執(zhí)行诉濒。

28. 什么是 CyclicBarrier 和 CountDownLatch?

CyclicBarrier 和 CountDownLatch 都是管理多線程編程所必需的夕春。但是它們之間有一些區(qū)別未荒,如下所示:

CyclicBarrier:它是一種使用某種算法同步線程處理的工具。它使一組線程相互等待及志,直到它們到達(dá)共同的執(zhí)行點(diǎn)或共同的障礙點(diǎn)片排,然后讓它們進(jìn)一步繼續(xù)執(zhí)行。即使通過設(shè)置屏障破壞了屏障速侈,也可以重復(fù)使用相同的 CyclicBarrier率寡。

CountDownLatch:它是一個(gè)工具,它可以讓主線程等待倚搬,直到強(qiáng)制操作被其他線程執(zhí)行并完成冶共。簡(jiǎn)而言之,它確保一個(gè)線程在開始執(zhí)行之前等待另一個(gè)線程中的執(zhí)行完成每界。一旦計(jì)數(shù)達(dá)到 0比默,就不能重用相同的 CountDownLatch。

29. 線程間通信是什么意思盆犁?

線程間通信命咐,顧名思義,是一種進(jìn)程或機(jī)制谐岁,多個(gè)線程可以使用該進(jìn)程或機(jī)制相互通信醋奠。它特別用于避免 java 中的線程輪詢,可以使用 wait()伊佃、notify() 和 notifyAll() 方法獲得窜司。

30. 什么是線程調(diào)度器和時(shí)間片?

線程調(diào)度器:它是 JVM 的一個(gè)組件航揉,用于在多個(gè)線程等待獲得執(zhí)行機(jī)會(huì)的情況下決定下一個(gè)線程將執(zhí)行塞祈。通過查看分配給每個(gè) READY 線程的優(yōu)先級(jí),線程調(diào)度程序選擇下一個(gè)運(yùn)行來執(zhí)行帅涂。線程調(diào)度主要使用兩種機(jī)制:搶占式調(diào)度和時(shí)間片調(diào)度议薪。

Time Slicing:它特別用于劃分CPU時(shí)間并將它們分配給活動(dòng)線程。在這種情況下媳友,每個(gè)線程將獲得一個(gè)預(yù)定義的時(shí)間片來執(zhí)行斯议。當(dāng)時(shí)間到期時(shí),特定線程必須等到其他線程有機(jī)會(huì)以循環(huán)方式使用它們的時(shí)間醇锚。每個(gè)正在運(yùn)行的線程都會(huì)在固定的時(shí)間段內(nèi)執(zhí)行哼御。

31.什么是關(guān)機(jī)鉤子?

關(guān)閉掛鉤只是在 JVM 關(guān)閉之前隱式調(diào)用的線程。它是 JVM 最重要的特性之一恋昼,因?yàn)樗峁┝诉M(jìn)行資源清理或保存 JVM 關(guān)閉的應(yīng)用程序狀態(tài)的能力看靠。通過調(diào)用 Runtime 類的 halt(int) 方法,可以停止關(guān)閉鉤子矩屁。使用以下方法空幻,可以添加關(guān)閉掛鉤鬓梅。

public void addShutdownHook(Thread hook){}     
Runtime r=Runtime.getRuntime();   
r.addShutdownHook(new MyThread());

32.什么忙轉(zhuǎn)活孩?

Busy Spinning崔涂,也稱為Busy-waiting,是一種線程等待某些條件發(fā)生的技術(shù)忧额,而不調(diào)用等待或睡眠方法并釋放CPU示启。在這種情況下谎仲,可以通過讓它運(yùn)行一個(gè)空循環(huán)一段時(shí)間來暫停一個(gè)線程旦部,它甚至不給 CPY 控制權(quán)。因此士八,它用于保留 CPU 緩存并避免重建緩存的成本醋虏。

33霞揉、什么是ConcurrentHashMap和Hashtable绊序?在java中,為什么ConcurrentHashMap被認(rèn)為比Hashtable快秽荞?

ConcurrentHashMap:它是在 Java 1.5 中引入的骤公,用于使用多個(gè)存儲(chǔ)桶存儲(chǔ)數(shù)據(jù)。顧名思義扬跋,它允許對(duì)地圖進(jìn)行并發(fā)讀寫操作阶捆。它只在進(jìn)行迭代時(shí)鎖定映射的特定部分以提供線程安全,以便其他讀取器仍然可以訪問映射而無需等待迭代完成钦听。

Hashtable:它是一個(gè)線程安全的遺留類洒试,在舊版本的 java 中引入,用于使用哈希表存儲(chǔ)鍵或值對(duì)朴上。與 ConcurrentHashMap 不同垒棋,它不提供任何無鎖讀取。它只是在進(jìn)行迭代時(shí)鎖定整個(gè)地圖痪宰。

ConcurrentHashMap 和 Hashtable 都是線程安全的叼架,但與 Hashtable 不同畔裕,ConcurrentHashMap 通常會(huì)避免讀鎖并提高性能。與 Hashtable 不同乖订,ConcurrentHashMap 還提供無鎖讀取柴钻。因此,ConcurrentHashMap 被認(rèn)為比 Hashtable 更快垢粮,尤其是當(dāng)讀取器的數(shù)量比寫入器的數(shù)量多時(shí)贴届。

34.解釋線程優(yōu)先級(jí)。

線程優(yōu)先級(jí)僅僅意味著具有最高優(yōu)先級(jí)的線程將在低優(yōu)先級(jí)線程之前獲得執(zhí)行的機(jī)會(huì)蜡吧『硫荆可以指定優(yōu)先級(jí),但最高優(yōu)先級(jí)線程不必在低優(yōu)先級(jí)線程之前執(zhí)行昔善。線程調(diào)度程序根據(jù)線程優(yōu)先級(jí)將處理器分配給線程元潘。優(yōu)先級(jí)范圍從最低優(yōu)先級(jí)到最高優(yōu)先級(jí)在 1-10 之間變化。


image.png

35. Java中的ThreadLocal變量是什么意思君仆?

ThreadLocal 變量是由 Java ThreadLocal 類創(chuàng)建和提供的特殊類型的變量翩概。這些變量只允許被同一個(gè)線程讀寫靴跛。兩個(gè)線程無法看到彼此的 ThreadLocal 變量叮喳,因此即使它們執(zhí)行相同的代碼,也不會(huì)出現(xiàn)任何競(jìng)爭(zhēng)條件歼指,并且代碼將是線程安全的咖摹。

示例

public class ThreadLocalExp   
{   
     public static class MyRunnable implements Runnable    
   {   
       private ThreadLocal<Integer> threadLocal =   
              new ThreadLocal<Integer>();   
      @Override   
       public void run() {   
           threadLocal.set( (int) (Math.random() * 50D) );   
           try    
           {   
               Thread.sleep(1000);   
           } catch (InterruptedException e) {   
           }   
           System.out.println(threadLocal.get());   
       }   
   }   
   public static void main(String[] args)    
   {   
       MyRunnable runnableInstance = new MyRunnable();    
       Thread t1 = new Thread(runnableInstance);   
       Thread t2 = new Thread(runnableInstance);   
      // this will call run() method    
       t1.start();   
       t2.start();   
   }   
} 

輸出

10 
33 
10 33 

36.什么是信號(hào)量评姨?

信號(hào)量被認(rèn)為是一種線程同步結(jié)構(gòu),通常需要使用計(jì)數(shù)器來控制和管理對(duì)共享資源的訪問萤晴。它只是設(shè)置線程的限制吐句。信號(hào)量類在包 java.util.concurrent 中定義,可用于在線程之間發(fā)送信號(hào)以避免丟失信號(hào)或保護(hù)臨界區(qū)店读。它還可以用于實(shí)現(xiàn)資源池或有界集合嗦枢。

37. 解釋線程組。為什么我們不應(yīng)該使用它屯断?

ThreadGroup 是一個(gè)用于在單個(gè)對(duì)象中創(chuàng)建多組線程的類文虏。這組線程以三種結(jié)構(gòu)的形式存在,其中每個(gè)線程組都有一個(gè)父線程裹纳,但初始線程除外择葡。線程組也可以包含其他線程組。一個(gè)線程只被允許訪問關(guān)于它自己的線程組的信息剃氧,而不是其他線程組敏储。

以前在舊版本的 Java 中,唯一沒有線程組就無法工作的功能是 uncaughtException(Thread t, Throwable e)朋鞍。但是現(xiàn)在在 Java 5 版本中已添,有了 Thread.setUncaughtExceptionHandler(UncaughtExceptionHandler)妥箕。所以現(xiàn)在即使沒有線程組也可以工作畦幢,因此不需要使用線程組宇葱。

t1.setUncaughtExceptionHandler(new UncaughtExceptionHandler() 
{ 
@Override  
public void uncaughtException(Thread t, Throwable e)  
{  
System.out.println("exception occured:"+e.getMessage()); 
}  
}; 

38刊头、什么是ExecutorService接口黍瞧?

ExecutorService 接口基本上是 Executor 接口的子接口,具有一些額外的方法或特性原杂,有助于管理和控制線程的執(zhí)行印颤。它使我們能夠在線程上異步執(zhí)行任務(wù)。


image.png

例子:

import java.util.concurrent.ExecutorService;   
import java.util.concurrent.Executors;   
import java.util.concurrent.TimeUnit;   

public class TestThread {   
                                   public static void main(final String[] arguments) throws InterruptedException {   
ExecutorService e = Executors.newSingleThreadExecutor();   

     try {   
       e.submit(new Thread());   
        System.out.println("Shutdown executor");   
        e.shutdown();   
        e.awaitTermination(5, TimeUnit.SECONDS);   
  } catch (InterruptedException ex) {   
       System.err.println("tasks interrupted");   
  } finally {   

        if (!e.isTerminated()) {   
           System.err.println("cancel non-finished tasks");   
     }   
        e.shutdownNow();   
        System.out.println("shutdown finished");   
  }   
  }   

  static class Task implements Runnable {   

     public void run() {   

        try {   
        Long duration = (long) (Math.random() * 20);   
           System.out.println("Running Task!");   
           TimeUnit.SECONDS.sleep(duration);   
     } catch (InterruptedException ex) {   
           ex.printStackTrace();   
     }   
  }   
 }          
}   

輸出:

Shutdown executor 
shutdown finished

39穿肄、如果我們不重寫線程類的run()方法會(huì)發(fā)生什么年局?

如果我們不覆蓋 run() 方法,什么都不會(huì)發(fā)生咸产。編譯器不會(huì)顯示任何錯(cuò)誤矢否。它將執(zhí)行線程類的 run() 方法,我們不會(huì)得到任何輸出锐朴,因?yàn)?run() 方法的實(shí)現(xiàn)是空的兴喂。

**例子: **

class MyThread extends Thread { 
  //don't override run() method 
} 
public class DontOverrideRun { 
  public static void main(String[] args) { 
         System.out.println("Started Main."); 
         MyThread thread1=new MyThread(); 
      thread1.start(); 
         System.out.println("Ended Main."); 
  } 
} 

輸出:

Started Main. 
Ended Main.  

40.什么是鎖接口蔼囊?為什么使用鎖接口比使用同步塊更好焚志。?

Lock 接口是在 Java 1.5 中引入的膳沽,一般用作同步機(jī)制,為阻塞提供重要的操作痛阻。

使用 Lock 接口優(yōu)于 Synchronization 塊的優(yōu)點(diǎn):

  • Lock 接口的方法俏扩,即 Lock() 和 Unlock() 可以在不同的方法中調(diào)用。這是鎖接口相對(duì)于同步塊的主要優(yōu)勢(shì)嫉戚,因?yàn)橥綁K完全包含在單個(gè)方法中。
  • 與同步塊不同凤覆,鎖接口更靈活,確保等待時(shí)間最長(zhǎng)的線程獲得公平的執(zhí)行機(jī)會(huì)。

41略号、是否可以直接調(diào)用run()方法啟動(dòng)一個(gè)新線程?

不羽利,這根本不可能。您需要調(diào)用 start 方法來創(chuàng)建新線程匾浪,否則 run 方法不會(huì)創(chuàng)建新線程。相反捌年,它將在當(dāng)前線程中執(zhí)行。

42. 在多線程編程中托酸,每個(gè)線程都可以有自己的棧嗎?

當(dāng)然应结,這是可能的。在多線程編程中,每個(gè)線程在內(nèi)存中維護(hù)自己獨(dú)立的堆棧區(qū)域玷坠,因此每個(gè)線程彼此獨(dú)立而不是相互依賴。

結(jié)論

43. 結(jié)論

總的來說秕重,多線程是 Java 和現(xiàn)代軟件開發(fā)的一個(gè)非常重要的部分服鹅。這對(duì)于提高程序的效率非常有幫助,同時(shí)也減少了存儲(chǔ)資源的使用仗哨。在本文中萨醒,我們討論了與多線程相關(guān)的重要面試問題以及面試中最常被問到的答案,并將幫助您破解面試晓褪。

推薦教程:
練習(xí)
Java 開發(fā)人員技能

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末示惊,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子崭孤,更是在濱河造成了極大的恐慌,老刑警劉巖嗤形,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搔预,死亡現(xiàn)場(chǎng)離奇詭異历造,居然都是意外死亡侣监,警方通過查閱死者的電腦和手機(jī)橄霉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門覆糟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人麦箍,你說我怎么就攤上這事【魅兀” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵碟联,是天一觀的道長(zhǎng)部脚。 經(jīng)常有香客問我鹰椒,道長(zhǎng)淆珊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮听哭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己酸员,他們只是感情好呢燥,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著屁置,像睡著了一般。 火紅的嫁衣襯著肌膚如雪揪阶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死插龄,一個(gè)胖子當(dāng)著我的面吹牛糠雨,可吹牛的內(nèi)容都是我干的垮庐。 我是一名探鬼主播逗抑,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼褂傀,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼加勤!你這毒婦竟也來了仙辟?” 一聲冷哼從身側(cè)響起同波,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎欺嗤,沒想到半個(gè)月后煎饼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體翅阵,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年厕氨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了芹壕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片潘明。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖漏麦,靈堂內(nèi)的尸體忽然破棺而出号涯,到底是詐尸還是另有隱情,我是刑警寧澤坪蚁,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布筹我,位于F島的核電站们妥,受9級(jí)特大地震影響僵控,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜妈嘹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望精刷。 院中可真熱鬧,春花似錦吟策、人聲如沸旺芽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至贿肩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間屹徘,已是汗流浹背走趋。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留噪伊,地道東北人簿煌。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鉴吹,于是被迫代替她去往敵國(guó)和親姨伟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容