1.說說你知道的創建執行緒的方式
- 1、繼承Thread類,重寫run方法,2、實作Runnable介面,重寫run方法,3、實作Callable介面,重寫call方法,4、通過執行緒池創建執行緒,
2.說說Runnable和Callable的區別
- Callable可以回傳一個型別V,而Runnable不可以,Callable能夠拋出checked exception,而Runnable不可以,
- Future和FutureTask留給你們!我放GitHub上了(uphe)
3.說說通過線方程池創建執行緒的式
Executors.newCachedThreadPool();創建一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閑執行緒,若無可回收,則新建執行緒,Executors.newFixedThreadPool(10);創建一個定長執行緒池,可控制執行緒最大并發數,超出的執行緒會在佇列中等待,Executors.newScheduledThreadPool(10);創建一個定長執行緒池,支持定時及周期性任務執行,Executors.newSingleThreadExecutor();創建一個單執行緒化的執行緒池,它只會用唯一的作業執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行,- 阿里巴巴開發手冊上不推薦上面的創建方式,創建執行緒池推薦用ThreadPoolExecutor,其中ThreadPoolExecutor有七大引數,四大拒絕策略,
- 1、int corePoolSize 核心執行緒池大小,2、int maximumPoolSize 最大核心執行緒池大小,3、long keepAliveTime 超時存活時間,4、TimeUnit unit 超時單位,5、BlockingQueue workQueue 阻塞佇列,6、ThreadFactory threadFactory 執行緒工廠,用于創建執行緒,7、RejectedExecutionHandler handler 拒絕策略,
- 四大拒絕策略,這里通過銀行辦理業務的例子進行說明, 1、AbortPolicy()); 銀行滿了還有人進來,不處理,拋出例外(默認),2、CallerRunsPolicy(); 銀行滿了,不處理,哪里來的去哪里,一般拋給main執行緒,3、DiscardPolicy(); 銀行滿了,把該執行緒丟掉,不拋例外,4、DiscardOldestPolicy(); 銀行滿了,會和先來的執行緒競爭,不拋例外,
4.最大執行緒數是如何確定的呢
- 一般有兩種策略CPU密集型和IO密集型,所謂CPU密集型,也就是,幾核的CPU就定義為幾,我的是八核,所以定義為8,
Runtime.getRuntime().availableProcessors();獲取CPU的核數,IO密集型,就是判斷程式中有多少個非常耗IO執行緒的程式,最大執行緒池的大小要大于這個值即可,
5.說說synchronized和Lock的區別
- 1、synchronized是關鍵字,Lock是類,2、synchronized無法獲取鎖的狀態,Lock可以,3、synchronized會自動釋放鎖,Lock需要手動,4、synchronized沒有Lock鎖靈活(Lock鎖可以自己定制),
6.說說ReentrantLock的應用場景
- 1、ReentrantLock默認是非公平鎖,但它可以設定公平鎖,也就是誰先來的誰先獲得鎖new ReentrantLock(true),2、ReentrantLock可以回應中斷,也就是當兩個執行緒發生死鎖的時候,你把A執行緒中斷了,B執行緒可以正常運行,3、ReentrantLock可以通過tryLock()實作限時等待,這樣可以解決死鎖問題,
7.synchronized鎖的優化了解嗎
- synchronized在JDK1.6進行了鎖的優化,也就是當一個執行緒多次訪問一個同步代碼塊的時候,此時會記錄該執行緒的threadId也就是,當你再來訪問的時候,我就只需判斷threadId就行了,效率高,這屬于偏向鎖,
- 當有多個執行緒來的時候,那么這個鎖就會升級為輕量級鎖,也就是通過CAS,來進行嘗試獲取鎖,是一種自旋鎖的狀態,如果在短時間內可以獲得鎖,不會堵塞,而且節約了CUP背景關系切換的時間,
- 如果長時間沒有獲取到鎖,會消耗CUP的資源,因為在那一直死回圈,經過一個時間段后會升級為重量級鎖,會發生阻塞,其中鎖升級是不可逆的,
8.說說對volatile關鍵字的理解
- 三大特性保證可見性,不保證原子性,禁止指令重排,
- 在說volatile之前,需要講解一個東西,Java記憶體模型(Java Memory Model,JMM),當執行緒讀取記憶體中的一個變數時,會先把這個變數拷貝到CPU的高速快取區,然后對其進行操作,操作完成后,會把該變數寫入到記憶體中,在單執行緒中是不會出現任何問題的,但是在多執行緒中就會有問題,當執行緒1讀取了該變數a=1到快取區進行了加1操作,還沒寫到記憶體中,執行緒2讀取了記憶體中的變數a=1也進行加1操作,然后執行緒1寫入記憶體a=2,執行緒2也寫入a=2到記憶體,那么最后,該變數的值是2,而不是3(出現了執行緒安全問題),
- 我們想要當執行緒1進行了加1操作之后,讓執行緒2知道,這就是volatile的作用了,可以保證可見性,也就是,當執行緒1對a變數進行了加1操作,會直接寫入到記憶體中(立即馬上),并且通知執行緒2,變數被修改了,要求執行緒2緩沖區的值去記憶體中重新讀取,但是,加1操作不是原子性的(三步,首先讀取a變數的值,然后對其進行加1操作,然后賦值給a),也就是說,當執行緒1讀取a變數到緩沖區后,還沒有修改a的值,此時執行緒2進來了,讀取了a的值,并且對其進行了加1操作,由于可見性,會把執行緒1緩沖區的值進行修改,但是,執行緒1中的CPU已經讀取了緩沖區的值,而且是更新前的值,所以出現了執行緒安全問題,也是volatile不保證原子性的問題,于是就需要加1操作是原子性操作,于是就有了一個automic包,通過該包下的方法,可以實作加1的原子性操作(還有其他原子性操作),
- 所謂指令重排,也就是在不影響單執行緒程式程式結果的情況下進行最優執行排序
9.那你說說CAS吧
- CAS(Compare And Swap,比較并交換),如果我們想要修改某個值num,那么我們可以通過一個方法compareAndSet(5,6)意思是,我們期望num的值是5,如果是,就修改為6,但是這就會有一個問題,我們期望的num是5,如果有其他執行緒把5修改為了8,然后又修改為了5,最終是5,但是已經被修改過一次了,這就是ABA問題,我們可以通過AtomicStampedReference,也就是原子參考,在創建的時候,有一個印記,相當于版本號,每被修改一次,版本號都被更新,所以,當出現ABA問題的時候,我們就可以清楚的知道,被修改了多少次,
10.AQS了解嗎
- 不了解,回家等通知吧,了解的或者是感覺上面有問題的可以私聊我,我們一起探討【賀賀學編程】
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/257447.html
標籤:java
