介紹一下Syncronized鎖。如果用這個(gè)關(guān)鍵字修飾一個(gè)靜態(tài)方法,鎖住了什么?如果修飾成員方法,鎖住了什么?
修飾靜態(tài)方法、修飾成員變量:相當(dāng)于全局鎖,相當(dāng)于鎖住了整個(gè)類。
synchronized(this)以及非static的synchronized方法(至于static synchronized方法請(qǐng)往下看),只能防止多個(gè)線程同時(shí)執(zhí)行同一個(gè)對(duì)象的同步代碼段
介紹一下volatile
保證可見性,有序性
當(dāng)把變量聲明為volatile類型后,編譯器與運(yùn)行時(shí)都會(huì)注意到這個(gè)變量是共享的,因此不會(huì)將該變量上的操作與其他內(nèi)存操作一起重排序。volatile變量不會(huì)被緩存在寄存器或者對(duì)其他處理器不可見的地方,因此在讀取volatile類型的變量時(shí)總會(huì)返回最新寫入的值。
在訪問volatile變量時(shí)不會(huì)執(zhí)行加鎖操作,因此也就不會(huì)使執(zhí)行線程阻塞,因此volatile變量是一種比sychronized關(guān)鍵字更輕量級(jí)的同步機(jī)制。
而聲明變量是 volatile 的,JVM 保證了每次讀變量都從內(nèi)存中讀
lock(防止指令重排序)
在執(zhí)行程序時(shí)為了提高性能,編譯器和處理器通常會(huì)對(duì)指令做重排序:
編譯器重排序。編譯器在不改變單線程程序語(yǔ)義的前提下,可以重新安排語(yǔ)句的執(zhí)行順序;
處理器重排序。如果不存在數(shù)據(jù)依賴性,處理器可以改變語(yǔ)句對(duì)應(yīng)機(jī)器指令的執(zhí)行順序;
多線程中的i++線程安全嗎?為什么?
局部變量中安全,全局變量不安全。
i++不是原子性操作,相當(dāng)于int tp1 = i; int tp2 = tp1+1; i = tp2;?
如何線程安全的實(shí)現(xiàn)一個(gè)計(jì)數(shù)器?
使用AtomicInteger 等原子類。
給i++加鎖
線程同步有哪幾種方式
1.同步方法
2.同步代碼塊??
3.使用特殊域變量(volatile)實(shí)現(xiàn)線程同步
4.使用重入鎖實(shí)現(xiàn)線程同步?
5.使用局部變量實(shí)現(xiàn)線程同步 (使用ThreadLocal管理變量)
6.wait與notify
7.使用原子變量實(shí)現(xiàn)線程同步
concurrenthashmap有啥優(yōu)勢(shì),1.7,1.8區(qū)別
http://www.importnew.com/23610.html
AQS(AbstractQueuedSynchronized)
Java并發(fā)之AQS詳解 - CodesGeek - 博客園
CAS(Compare And Swap?)
如果V值等于E值,則將V的值設(shè)為N。若V值和E值不同,則說明已經(jīng)有其他線程做了更新,則當(dāng)前線程什么都不做。
通俗的理解就是CAS操作需要我們提供一個(gè)期望值,當(dāng)期望值與當(dāng)前線程的變量值相同時(shí),說明還沒線程修改該值,當(dāng)前線程可以進(jìn)行修改,也就是執(zhí)行CAS操作,但如果期望值與當(dāng)前線程不符,則說明該值已被其他線程修改,此時(shí)不執(zhí)行更新操作,但可以選擇重新讀取該變量再嘗試再次修改該變量,也可以放棄操作
ABA
比如說一個(gè)線程one從內(nèi)存位置V中取出A,這時(shí)候另一個(gè)線程two也從內(nèi)存中取出A,并且two進(jìn)行了一些操作變成了B,然后two又將V位置的數(shù)據(jù)變成A,這時(shí)候線程one進(jìn)行CAS操作發(fā)現(xiàn)內(nèi)存中仍然是A,然后one操作成功。盡管線程one的CAS操作成功,但是不代表這個(gè)過程就是沒有問題的。如果鏈表的頭在變化了兩次后恢復(fù)了原值,但是不代表鏈表就沒有變化。因此前面提到的原子操作。
各種樂觀鎖的實(shí)現(xiàn)中通常都會(huì)用版本戳version來對(duì)記錄或?qū)ο髽?biāo)記,避免并發(fā)操作帶來的問題。
線程安全的Map都有啥,Collections.synchronizedmap(),ConcurrentHashMap,Hashtable 底層實(shí)現(xiàn)
線程池運(yùn)行流程,參數(shù),策略
線程池相關(guān)筆記,線程池的實(shí)現(xiàn)?四種線程池?重要參數(shù)及原理?任務(wù)拒接策略有哪幾種? - CSDN博客
synchronized,偏向鎖,輕量級(jí)鎖,重量級(jí)鎖,鎖膨脹機(jī)制
Synchronized的原理及自旋鎖,偏向鎖,輕量級(jí)鎖,重量級(jí)鎖的區(qū)別 - CSDN博客
wait方法底層原理?join,notify,notifyall
多線程(二):詳細(xì)描述wait、notify/notifyAll、join及底層實(shí)現(xiàn) - CSDN博客
線程池原理
講一下非公平鎖和公平鎖在reetrantlock里的實(shí)現(xiàn)。
FairSync 公平鎖?
公平鎖就是每個(gè)線程在獲取鎖時(shí)會(huì)先查看此鎖維護(hù)的等待隊(duì)列,如果為空,或者當(dāng)前線程線程是等待隊(duì)列的第一個(gè),就占有鎖,否則就會(huì)加入到等待隊(duì)列中,以后會(huì)按照FIFO的規(guī)則從隊(duì)列中獲取,
講一下synchronized,可重入怎么實(shí)現(xiàn)
Java中一個(gè)線程在通過synchronized獲取到一個(gè)對(duì)象的對(duì)象鎖后會(huì)阻塞試圖獲取該對(duì)象鎖的其他線程,但不會(huì)阻塞當(dāng)前線程,也就是說synchronized代碼塊對(duì)當(dāng)前線程來說是可重入的
多線程實(shí)現(xiàn)方法
繼承Thread類創(chuàng)建線程類,重寫run方法,run方法就是代表線程需要完成的任務(wù),調(diào)用線程對(duì)象的start()來啟動(dòng)該線程,線程類已經(jīng)繼承了Thread類,所以不能再繼承其他父類。? ?
實(shí)現(xiàn)Runnable接口創(chuàng)建線程類,定義Runnable實(shí)現(xiàn)類,重寫run方法? ?
實(shí)現(xiàn)Callable接口,重寫call()方法,call()作為線程的執(zhí)行體,具有返回值? ?
線程池,使用線程池產(chǎn)生線程對(duì)象java.util.concurrent.ExecutorService、java.util.concurrent.Executors;
Synchronized和lock區(qū)別
Lock提供了synchronized關(guān)鍵字所不具備的主要特性有:
嘗試非阻塞地獲取鎖boolean tryLock():當(dāng)前線程嘗試獲取鎖,如果這一時(shí)刻沒有被其他線程獲取到,則成功獲取并持有鎖? ? ? ?
能被中斷地獲取鎖void lockInterruptibly():當(dāng)獲取到鎖的線程被中斷時(shí),中斷異常拋出同時(shí)會(huì)釋放鎖? ? ? ?
超時(shí)獲取鎖boolean trylock(long time, TimeUnit unit):在指定截止時(shí)間之前獲取鎖,如果在截止時(shí)間仍舊無法獲取鎖,則返回? ? ?
synchronized是JVM提供的加鎖,悲觀鎖;lock是Java語(yǔ)言實(shí)現(xiàn)的,而且是樂觀鎖。? ?
ReentrantLock是基于AQS實(shí)現(xiàn)的,由于AQS是基于FIFO隊(duì)列的實(shí)現(xiàn)
Java中都有什么鎖
重量級(jí)鎖、顯式鎖、并發(fā)容器、并發(fā)同步器、CAS、volatile、AQS等
可重入鎖的設(shè)計(jì)思路是什么
可重入公平鎖獲取流程
在獲取鎖的時(shí)候,如果當(dāng)前線程之前已經(jīng)獲取到了鎖,就會(huì)把state加1,在釋放鎖的時(shí)候會(huì)先減1,這樣就保證了同一個(gè)鎖可以被同一個(gè)線程獲取多次,而不會(huì)出現(xiàn)死鎖的情況。這就是ReentrantLock的可重入性。
對(duì)于非公平鎖而言,調(diào)用lock方法后,會(huì)先嘗試搶占鎖,在各種判斷的時(shí)候會(huì)先忽略等待隊(duì)列,如果鎖可用,就會(huì)直接搶占使用。
樂觀鎖和悲觀鎖
悲觀鎖:假定會(huì)發(fā)生并發(fā)沖突,則屏蔽一切可能違反數(shù)據(jù)完整性的操作
樂觀鎖:假定不會(huì)發(fā)生并發(fā)沖突,只在數(shù)據(jù)提交時(shí)檢查是否違反了數(shù)據(jù)完整性(不能解決臟讀問題)
juc包內(nèi)有哪些類
CountDownLatch 同步計(jì)數(shù)器,主要用于線程間的控制,但計(jì)數(shù)無法被重置,如果需要重置計(jì)數(shù),請(qǐng)考慮使用 CyclicBarrier 。
線程池新任務(wù)到達(dá)時(shí)會(huì)先使用空閑線程還是加入阻塞隊(duì)列
Java并發(fā)包里面的CountdownLatch怎么使用
這個(gè)類是一個(gè)同步計(jì)數(shù)器,主要用于線程間的控制,當(dāng)CountDownLatch的count計(jì)數(shù)>0時(shí),await()會(huì)造成阻塞,直到count變?yōu)?,await()結(jié)束阻塞,使用countDown()會(huì)讓count減1。CountDownLatch的構(gòu)造函數(shù)可以設(shè)置count值,當(dāng)count=1時(shí),它的作用類似于wait()和notify()的作用。如果我想讓其他線程執(zhí)行完指定程序,其他所有程序都執(zhí)行結(jié)束后我再執(zhí)行,這時(shí)可以用CountDownLatch,但計(jì)數(shù)無法被重置,如果需要重置計(jì)數(shù),請(qǐng)考慮使用 CyclicBarrier 。
volatile和synchronized區(qū)別
volatile是變量修飾符,其修飾的變量具有可見性,Java的做法是將該變量的操作放在寄存器或者CPU緩存上進(jìn)行,之后才會(huì)同步到主存,使用volatile修飾符的變量是直接讀寫主存,volatile不保證原子性,同時(shí)volatile禁止指令重排? ?
synchronized作用于一段代碼或者方法,保證可見性,又保證原子性,可見性是synchronized或者Lock能保證通一個(gè)時(shí)刻只有一個(gè)線程獲取鎖然后執(zhí)行不同代碼,并且在釋放鎖之前會(huì)對(duì)變量的修改刷新到主存中去,原子性是指要么不執(zhí)行,要執(zhí)行就執(zhí)行到底
一般線程和守護(hù)線程的區(qū)別
java中的線程分為兩種:守護(hù)線程(Daemon)和用戶線程(User)。
任何線程都可以設(shè)置為守護(hù)線程和用戶線程,通過方法Thread.setDaemon(bool on);true則把該線程設(shè)置為守護(hù)線程,反之則為用戶線程。Thread.setDaemon()必須在Thread.start()之前調(diào)用,否則運(yùn)行時(shí)會(huì)拋出異常。
唯一的區(qū)別是判斷虛擬機(jī)(JVM)何時(shí)離開,Daemon是為其他線程提供服務(wù),如果全部的User Thread已經(jīng)撤離,Daemon 沒有可服務(wù)的線程,JVM撤離。也可以理解為守護(hù)線程是JVM自動(dòng)創(chuàng)建的線程(但不一定),用戶線程是程序創(chuàng)建的線程;比如JVM的垃圾回收線程是一個(gè)守護(hù)線程,當(dāng)所有線程已經(jīng)撤離,不再產(chǎn)生垃圾,守護(hù)線程自然就沒事可干了,當(dāng)垃圾回收線程是Java虛擬機(jī)上僅剩的線程時(shí),Java虛擬機(jī)會(huì)自動(dòng)離開。