說一說自己對于 synchronized 關(guān)鍵字的了解
synchronized關(guān)鍵字解決多個線程之間訪問資源的同步性,被synchronized關(guān)鍵字能保證被他修飾的方法和代碼塊在任意時刻都只有一個線程訪問
說說自己是怎么使用 synchronized 關(guān)鍵字,在項目中用到了嗎
synchronized關(guān)鍵字主要用于三種場景:①修飾實例方法:也就是給當前實例對象加鎖,當進入到同步代碼塊之前需要獲得當前對象的鎖②修飾靜態(tài)方法:也就是給當前類加鎖,作用于改類的所有實例對象,而靜態(tài)資源是不屬于實例對象的,是屬于類的。所以如果有一個線程訪問synchronized修飾的非靜態(tài)方法,另一個線程訪問synchronize修飾的靜態(tài)方法,是不會出現(xiàn)互斥的。因為synchronized修飾的非靜態(tài)方法是當前實例對象的鎖,而synchronize修飾的靜態(tài)方法是類的鎖。③修飾代碼塊:也就是給給定對象加鎖,在訪問同步代碼塊之前需要獲得給定對象的鎖
什么是雙重檢查鎖實現(xiàn)單例?代碼是什么樣子的?
雙重檢查鎖實現(xiàn)單例就是在創(chuàng)建單例對象的時候會進行兩次判斷實例是否存在,一次加鎖判斷一次不加鎖判斷
代碼:

說說 JDK1.6 之后的synchronized 關(guān)鍵字底層做了哪些優(yōu)化,可以詳細介紹一下這些優(yōu)化嗎
JDK1.6版本之后,對鎖的做了很多優(yōu)化,比如說:偏向鎖,自旋鎖,輕量級鎖,鎖粗化等技術(shù)來減少鎖操作的開銷。鎖的狀態(tài)有四種,分別是:無鎖狀態(tài),偏向鎖狀態(tài),輕量級鎖狀態(tài)和重量級鎖狀態(tài),他們會隨著競爭的激烈而提升,鎖是可以提升但不可以降級,這種策略是為了提高獲得鎖和釋放鎖的效率。
談?wù)?synchronized和ReentrantLock 的區(qū)別
相同:他們都是可重入鎖
區(qū)別:①synchronized在競爭鎖的時候會一直等待,ReentrantLock會嘗試去獲取鎖,并將獲取結(jié)果返回
②synchronized獲取鎖的時候不能設(shè)置超時時間,ReentrantLock可以設(shè)置超時時間
③synchronized不能滿足公平鎖,而ReentrantLock可以滿足公平鎖
④synchronized是依賴于JVM的,而ReentrantLock是依賴于JDK的API
⑤synchronized在執(zhí)行鎖代碼塊的時候出現(xiàn)異常會自動釋放鎖,而ReentrantLock不會,他需要在finally{}中釋放鎖
并發(fā)編程的三大特征以及volatile關(guān)鍵字的作用?
并發(fā)編程有三大特性,分別是:①原子性:一個操作或多次操作在執(zhí)行過程中要么全部執(zhí)行完成,要么全部不執(zhí)行②可見性:當一個變量對共享變量進行修改值時,其他線程也可以同時第一時間獲得變量修改之后的值③有序性:代碼執(zhí)行過程中是有序的
volatile關(guān)鍵字可以保證可變變量的可見性以及防止指令重排序
說說 synchronized 關(guān)鍵字和 volatile 關(guān)鍵字的區(qū)別
synchronized關(guān)鍵字和volatile關(guān)鍵字的作用是互補的
①volatile關(guān)鍵字是線程同步的輕量級實現(xiàn),所以他的性能比synchronized的性能要高,但是volatile關(guān)鍵字只能修飾變量,而synchronized關(guān)鍵字可以修飾方法和代碼塊,所以我們使用synchronized關(guān)鍵字的場景比較多。②多線程訪問volatile關(guān)鍵字不會發(fā)生線程堵塞,但是訪問synchronize關(guān)鍵字可能會發(fā)生堵塞③volatile關(guān)鍵字能保證數(shù)據(jù)的可見性,但不能保證數(shù)據(jù)的原子性,而synchronized關(guān)鍵字兩者都能保證④volatile關(guān)鍵字主要解決于多線程之間的變量可見性,而synchronized關(guān)鍵字主要是解決多線程之間的訪問資源的同步性
ThreadLocal有什么作用?有哪些使用場景?
ThreadLocal是線程本地存儲。每個線程都創(chuàng)建一個ThreadLocalMap對象,然后每個線程都可以訪問自己的ThreadLocalMap對象中的value。通過這種方法,可以避免資源在多線程之間的共享。
常用的使用場景是給每一個線程分配一個JDBC的連接對象,這樣子就可以保證
什么是線程池?
線程池就是創(chuàng)建若干個線程存放到一個池里面,當有任務(wù)需要處理的時候,就到線程池中 的任務(wù)隊列中,等任務(wù)執(zhí)行完成之后,線程不會被銷毀,而是回到線程池中等待下一個任務(wù)。
線程池的優(yōu)點
線程池的特點是:線程可復用? 可設(shè)置最大并發(fā)量? ? 可管理線程
線程池的優(yōu)點是:降低資源消耗? 提高響應效率? ? 提高線程的可管理性
實現(xiàn)Runnable接口和Callable接口的區(qū)別
①Runnable的run()方法只能拋出運行時異常,并且不能處理,而Callable的call()方法可以捕捉異常,并且返回異常信息②Runnable的run()方法沒有返回值,Callable的call()方法有返回值,并且支持泛型
執(zhí)行execute()方法和submit()方法的區(qū)別是什么呢?
execute()方法用于提交不需要返回值的任務(wù),任務(wù)提交之后我們沒法判斷任務(wù)是否在線程池中成功完成submit()方法用于提交需要返回值的任務(wù),線程池會返回一個Future對象,我們可以通過Future對象判斷任務(wù)是否成功完成,并且可以跳過Futrue中的get()方法獲取到返回值
如何創(chuàng)建線程池?
我們可以通過兩種方式來創(chuàng)建線程池:
第一種是通過構(gòu)造器來實現(xiàn),也就是ThreadPoolExecutor
第二種是通過Executor的工具類Executors來實現(xiàn),我們可以創(chuàng)建三種線程池
FixedThreadPool:創(chuàng)建返回指定線程數(shù)量的線程池
SingleThreadExecutor:創(chuàng)建只返回一個線程對象的線程池
CacheThreadPool:創(chuàng)建可以根據(jù)實際情況創(chuàng)建線程數(shù)量的線程池
線程池的原理分析(執(zhí)行流程)
當一個任務(wù)提交的時候回到線程池中判斷核心線程數(shù)數(shù)量是否已經(jīng)達到最大,如果不是的話就會創(chuàng)建一個線程,如果是的話就到任務(wù)隊列中看是否已滿,如果沒滿的話就會到任務(wù)隊列中排隊,如果滿了的話就判斷線程池的最大線程數(shù)是否已達到最大,如果沒有則創(chuàng)建線程,如果已經(jīng)達到最大的話就會執(zhí)行RejectedExecutionHandle方法拒絕此次任務(wù)提交
介紹一下Atomic 原子類
Atomic就是原子類,在這里的意思是一旦操作執(zhí)行就不會被打斷,就算多個線程同時在執(zhí)行,操作一旦開始,不會受其他線程的影響。它具有原子性的特征
什么是JUC
JUC是java.util.concurrent包的簡稱,他是一個工具包,里面包含了很多原子類,這些原子類可以更好的提高線程的高并發(fā),已經(jīng)避免多線程執(zhí)行過程中出現(xiàn)死鎖的情況
JUC 包中的原子類是哪4類?
JUC包中包括四種原子性類,分別是:整形原子型,數(shù)組類型原子型,引用類型原子型,基于對象類型修改原子型
整形原子型的類有:AtomicIntegerAtomicLongAtomicBoolean數(shù)組類型原子型:AtomicIntegerArrayAtomicLongArrayAtomicReferenceArray引用類型原子型:AtomicReferenceAtomicStamtedReferenceAtomicMarkableReference基于對象類型修改原子型:AtomicStmtedReferenceAtomicIntegerFieldUpdater AtomicLongFieldUpdater?
講講 AtomicInteger 的使用
AtomicInteger中有很多方法,比如getAndSet() , getAndIncrement() , getAndAdd()等方法,而我們使用的時候就創(chuàng)建一個AtomicInteger對象,然后調(diào)用對應的方法,再將調(diào)用方法后得出的結(jié)果賦值給一個int類型變量
能不能給我簡單介紹一下 AtomicInteger 類的原理
AtomicInteger類是Atomic原子類中的整形原子類中的一個類,他是通過CAS(compare and swap)和volatile以及native方法來保證原子性操作,從而減少synchronize關(guān)鍵字的開銷,提高執(zhí)行效率
AQS 原理概覽
AQS的基本原理就是:當一個請求進入到共享資源的時候,會判斷這個共享資源是否為空閑,如果是的話就將當前這個線程設(shè)置成有效工作線程,并且將共享資源給鎖住;如果不是的話,就會進入線程阻塞等待以及喚醒的時候分配鎖的一個機制,這個機制是由CLH的隊列鎖實現(xiàn)的,如果暫時沒有分配到鎖的線程就會進入到隊列中
shutdown() VS shutdownNow()
shutdown():關(guān)閉線程池,不再接受新的任務(wù),但是回將隊列里的任務(wù)執(zhí)行完畢shutdownNow():關(guān)閉線程池,停止當前正在執(zhí)行的任務(wù),并且將隊列中的任務(wù)停止處理,并將正在排隊的返回一個List
常用的線程池
FixedThreadPool
SecheduledThreadPoolExecutor
CachedThreadPool
SingleThreadExecutor
什么是悲觀鎖和樂觀鎖
樂觀鎖:他總是很樂觀,覺得不會發(fā)生并發(fā)問題,在他讀取數(shù)據(jù)的時候覺得不會有其他線程來修改數(shù)據(jù),所以不加鎖,但是在修改數(shù)據(jù)的時候他會去判斷在此之前是否有其他線程對數(shù)據(jù)進行修改,通常是使用CAS和版本號機制來操作
悲觀鎖:他總是很悲觀,他覺得在數(shù)據(jù)讀取的時候會有其他線程來修改數(shù)據(jù),所以他總是加鎖,如果其他線程要獲取該數(shù)據(jù)的話,會出現(xiàn)阻塞狀態(tài),然后等到鎖的時候再讀取數(shù)據(jù)