Q:什么是線程?什么是進程?線程和進程有什么區(qū)別?
A:線程:又稱"輕量級進程",是操作系統(tǒng)能夠進行運算調度的最小單位,被包含在進程之中,是進程中的實際運作單位。
進程: 系統(tǒng)進行資源分配和調度的基本單位。
兩者之間的區(qū)別:
地址空間和其他資源:進程間相互獨立,同一進程的各線程間共享,某進程中的線程在其他進程不可見。
通信:進程間通信 IPC,線程間可以直接讀寫進程數(shù)據(jù)段(如全局變量)來進行通信——需要進程同步和互斥手段的輔助,以保證數(shù)據(jù)的一致性。
調度和切換:線程上下文切換比進程上下文切換要快得多。
在多線程 OS 中,進程不是一個可執(zhí)行的實體。
Q:多線程編程的好處是什么?
A:發(fā)揮多核 CPU 的優(yōu)勢(提高性能)、防止阻塞、便于建模。
Q:有幾種創(chuàng)建線程的方式?哪種比較好?
A:①、實現(xiàn) Runnable 接口(較好:靈活,減少耦合度);②、繼承 Thread 類。
Q:Runnable 接口和 Callable 接口的區(qū)別?
A:Callable 接口中的 call() 方法是可以返回值和拋出異常,是一個泛型,和 Future / FutureTask 配合來獲取結果。而 Runnalbe 接口的 run() 方法,無返回值。
Q:Java 中 CyclicBarrier 和 CountDownLatch 有什么不同?
A:①、CyclicBarrier 是 n 個線程,相互等待;CountDownLatch 是一個或多個線程,等待另外 n 個線程執(zhí)行完,再執(zhí)行。
②、CyclicBarrier 加計數(shù);CountDownLatch 減計數(shù)。
③、CyclicBarrier 計數(shù)達到指定值時,計數(shù)置為 0 重新開始;CountDownLatch 計數(shù)為 0 時,無法重置。(不可重復利用)
④、CyclicBarrier 調用 await() 方法計數(shù)加 1 , 若加 1 后的值不等于構造方法的值,則線程阻塞;CountDownLatch 調用 countDown() 方法計數(shù)減 1 ,調用 await() 方法只進行阻塞,對計數(shù)沒任何影響。
Q:volatile 是什么?作用是什么?
A:volatile 是一個類型修飾符,是用來修飾被不同線程訪問和修改的變量。
主要作用有兩個:①、內存可見性,即線程 A 對 volatile 變量的修改,其他線程獲取的 volatile 變量都是最新的;②、可以禁止指令(程序執(zhí)行的順序)重排序。
Q:什么是線程安全?
A:線程安全:多線程訪問時,采用了加鎖機制,當一個數(shù)據(jù)訪問該類的某個數(shù)據(jù)時,進行保護,其他線程不能進行訪問直到該線程讀取完,其他線程才可使用。不會出現(xiàn)數(shù)據(jù)不一致或者數(shù)據(jù)污染。
線程不安全:不提供數(shù)據(jù)訪問保護,有可能多個線程先后更改數(shù)據(jù)造成所得到的數(shù)據(jù)是臟數(shù)據(jù)。
Q:線程安全分為哪幾種級別?
A:①、不可變:不變的對象絕對是線程安全的,不需要線程同步,如 String、Long、BigInteger;
②、無條件的線程安全:對象自身做了足夠多的內部同步,也不需要外部同步,如 Random、ConcurrentHahsMap、Concurrent 集合、atomic;
③、有條件的線程安全:對象的部分方法可以無條件安全使用,但是有些地方需要外部同步,需要 Collectiongs.synchronized;有條件線程安全的最常見的例子是遍歷由 HashTable 或者 Vector 或者返回的迭代器;
④、非線程安全(線程兼容):對象本身不提供線程安全機制,但是通過外部同步,可以在并發(fā)環(huán)境使用,如 ArrayList、HashMap;
⑤、線程對立:即使外部進行了同步調用,也不能保證線程安全,這種情況非常少,如 System.setOut()、System.runFinalizersOnExit()。
Q:如何正確地停止一個線程?
A:①、使用退出標志,使線程正常退出,也就是當 run 方法完成后線程終止;
②、使用 interrupt 方法中斷線程;
③、使用 stop 方法強行終止,但是不推薦使用,因為 stop 和 suspend 以及 resume 一樣存在死鎖威脅,并且都是過期作廢的方法。
Q:一個線程運行時發(fā)生異常會怎樣?
A:①、如果異常沒有被捕獲,該線程將會停止執(zhí)行。
②、如果這個線程持有某個對象的監(jiān)視器,那么這個對象監(jiān)視器會被立即釋放。
Q:兩個線程之間,如何實現(xiàn)數(shù)據(jù)共享?
A:①、使用同一個 Runnable 對象;
②、使用不同的 Runnable 對象:
i、將共享數(shù)據(jù)分別傳遞給兩個不同的線程;
ii、將這些 Runnable 對象作為一個內部類,將共享數(shù)據(jù)作為成員變量。
Q:sleep() 方法和 wait() 方法有什么區(qū)別?
A:①、所在的類:sleep 在 Thread 類中、wait 在 Object 類中;
②、鎖:sleep 方法沒有釋放鎖、wait 方法釋放了鎖;
③、使用范圍:sleep 可以在任何地方使用、而 wait,notify 和 notifyAll 只能在同步控制方法或者同步控制塊里面使用。
Q:ThreadLoacl 是什么?作用是什么?
A:它是線程局部變量,每個線程都有自己的 ThreadLocal。
作用:把數(shù)據(jù)進行隔離,數(shù)據(jù)不共享(空間換時間,在 Thread 中維護了一個以開地址法實現(xiàn)的 ThreadLocalMap )。
Q:為什么 wait() 方法和 notify()/notifyAll() 方法要在同步塊( synchronized )中被調用?
A:JDK 強制的,方法調用之前必須先獲得對象的鎖。如果不這樣做,就會拋出 IllegalMonitorStateException 異常。
Q:同步集合 & 并發(fā)集合的區(qū)別?
A:都支持線程安全,主要區(qū)別體現(xiàn)在性能和可擴展性。
性能:同步集合會把整個 Map 或者 List 鎖起來,而并發(fā)集合不會。所以同步集合比并發(fā)集合慢的多。
可擴展性:并發(fā)集合不僅提供線程安全,還用鎖分離和內部分區(qū)等現(xiàn)代技術來提高可擴展性。
Q:什么是線程池? 為什么要使用它?
A:在程序啟動時,就創(chuàng)建若干個線程來響應請求。使用它,可以避免頻繁地創(chuàng)建和銷毀線程,達到線程對象的重用,還可以根據(jù)項目靈活地控制并發(fā)的數(shù)目。
Q:什么是死鎖?死鎖發(fā)生的必要條件?如何避免死鎖?
A:死鎖:兩個及以上的進程在執(zhí)行過程中,因爭奪資源而造成的一種互相等待的現(xiàn)象,若無外力作用,他們都將無法推進下去。
死鎖的必要條件:
①、互斥條件:一個資源每次只能被一個進程使用;
②、請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不變;
③、不剝奪條件:進程已獲得的資源,在未使用之前,不能強行剝奪;
④、循環(huán)等待條件:若干進程之間形成一種頭尾相連的循環(huán)等待資源關系。避免死鎖最簡單的方法:阻止循環(huán)等待條件,將系統(tǒng)中所有的資源設置標志位、排序,規(guī)定所有的進程申請資源必須以一定的順序做操作。
Q:活鎖 & 死鎖的區(qū)別?
A:活鎖進程的狀態(tài)可以改變但是卻不能繼續(xù)執(zhí)行。
Q:怎么檢測一個線程是否擁有鎖?
A:Thread 中的 holdsLock() 方法:如果當且僅當當前線程擁有某個具體對象的鎖時,返回 true。
Q:synchronized & ReentrantLock 的區(qū)別?
A:兩者都是加鎖方式同步(阻塞式同步)。
其本質上的區(qū)別:synchronized 是關鍵字,ReentrantLock 是類。
相對于 synchronized 而言,ReentrantLock 類提供了一些高級功能:
①、等待可中斷:持有鎖的線程長期不釋放時,正在等待的線程可以選擇放棄等待,這相等于 synchronized 來說,避免了死鎖;
②、公平鎖:synchronized 只能是非公平鎖,ReenTrantLock 可以通過構造函數(shù)的參數(shù)來指定公平鎖和非公平鎖。(公平鎖:先等待的線程先得到鎖);
③、鎖綁定多個條件:一個 ReentrantLock 對象可以同時綁定多個對象。
④、鎖機制不一樣:synchronized
Q:如何保證線程按照指定順序執(zhí)行?
A:使用 new Thread().join() 方法:等待線程結束。也就是說通過一個線程等待另一個線程執(zhí)行完畢,再繼續(xù)執(zhí)行,來實現(xiàn)。
Q:如果你提交任務時,線程池隊列已滿。會時發(fā)會生什么?
A:當一個任務不能被調度執(zhí)行時,ThreadPoolExecutor 的 submit() 方法將會拋出 RejectedExecutionException 異常。
Q:Java 線程池中 submit() & execute() 方法有什么區(qū)別?
A:①、接收的參數(shù)不一樣;②、submit() 有返回值,execute() 沒有
;③、submit() 方便 Exception 處理。
Q:ReadWriteLock 是什么?
A:維護一對關聯(lián)的鎖,一個用于只讀操作,一個用于寫操作。讀鎖是共享的,而寫鎖是獨占的。
Q:多線程中的忙循環(huán)是什么?使用它的目的是什么?
A:忙循環(huán):用循環(huán)讓一個線程等待,不會放棄 CPU。
目的:為了保留 CPU 緩存,避免重建緩存和減少等待重建時間。在多核系統(tǒng)中,一個等待線程醒來時,可能會在另一個內核運行,這樣就會重建緩存。
Q:遵循的多線程的最佳實踐有哪幾條?
A:①、給線程起一個有意義的名字;②、避免鎖定和縮小同步的范圍;③、多用同步類,少用 wait 和 notify;④、多用并發(fā)集合,少用同步集合。
Q:如何強制啟動一個線程?
A:它是被線程調度器控制的,并且 Java 沒有公布相關的 API。
Q:fork-join 框架是什么?
A:Java7 提供了的一個用于并行執(zhí)行任務的框架, 是一個把大任務分割成若干個小任務,最終匯總每個小任務結果后得到大任務結果的框架。使用了工作竊取算法。