久久亚洲成a人片熟女精品色一区二区三区|国产精品视频第一精品视频|av天堂热无码手机版|亚洲?v无码久久无遮挡|国产精品偷伦视频免费观看国产|麻豆国产自产精品丰满熟妇|av无码av不卡一区二区|久久亚洲精品中文字

ARTICLE DETAIL

資訊詳情

深耕商務(wù)建站與企業(yè)官網(wǎng)運(yùn)營(yíng)的一線實(shí)戰(zhàn)洞察。

Java并發(fā)編程核心知識(shí)詳解:線程、鎖與線程池實(shí)戰(zhàn)

Java并發(fā)編程核心知識(shí)詳解:線程、鎖與線程池實(shí)戰(zhàn) 1. 線程基礎(chǔ)先搞清楚線程到底是什么線程這塊內(nèi)容可以說是Java面試?yán)锍鰣?chǎng)率最高的知識(shí)點(diǎn)沒有之一。不管是校招還是社招只要是后端方向幾乎必問線程相關(guān)的概念。我這些年面試別人也被別人面試發(fā)現(xiàn)線程八股問來問去核心就那么幾個(gè)方向線程的創(chuàng)建方式、生命周期、狀態(tài)流轉(zhuǎn)、線程池、鎖機(jī)制、并發(fā)工具類。把這些吃透了基本就能應(yīng)對(duì)絕大部分面試場(chǎng)景。先聊線程的本質(zhì)。線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位它被包含在進(jìn)程之中是進(jìn)程中的實(shí)際運(yùn)作單位。一條線程指的是進(jìn)程中一個(gè)單一順序的控制流一個(gè)進(jìn)程中可以并發(fā)多個(gè)線程每條線程并行執(zhí)行不同的任務(wù)。打個(gè)比方進(jìn)程就像一家餐廳線程就像餐廳里的服務(wù)員一個(gè)餐廳可以有多個(gè)服務(wù)員同時(shí)服務(wù)不同的顧客。Java天生支持多線程編程這也是Java能成為企業(yè)級(jí)開發(fā)主流語言的重要原因之一。很多初學(xué)者對(duì)線程和進(jìn)程的關(guān)系搞不清楚這里我多說一句。進(jìn)程是資源分配的基本單位線程是CPU調(diào)度的基本單位。進(jìn)程之間相互獨(dú)立各有獨(dú)立的地址空間同一個(gè)進(jìn)程內(nèi)的線程共享進(jìn)程的地址空間和資源。所以多線程編程最大的優(yōu)勢(shì)就是可以共享數(shù)據(jù)、節(jié)省資源但同時(shí)也帶來了并發(fā)安全問題這也是后面所有鎖機(jī)制存在的根本原因。從面試角度來說線程基礎(chǔ)這塊經(jīng)常被問到的一個(gè)問題是Java里創(chuàng)建線程有哪幾種方式這個(gè)問題看起來簡(jiǎn)單但其實(shí)有很多細(xì)節(jié)可以深挖。我遇到過很多候選人能說出繼承Thread類和實(shí)現(xiàn)Runnable接口但對(duì)Callable和FutureTask、以及線程池創(chuàng)建這幾種方式理解不夠深入。下面具體展開說。1.1 線程創(chuàng)建方式的演進(jìn)與對(duì)比Java創(chuàng)建線程的方式從最初的繼承Thread類到實(shí)現(xiàn)Runnable接口再到JDK 5引入的Callable和FutureTask以及最終的線程池經(jīng)歷了一個(gè)逐步演進(jìn)的過程。這個(gè)演進(jìn)過程本質(zhì)上是在解決如何更好地管理和復(fù)用線程這個(gè)問題。繼承Thread類是最傳統(tǒng)的方式直接new一個(gè)Thread的子類重寫run方法。這種方式代碼簡(jiǎn)單但缺點(diǎn)很明顯Java是單繼承的一旦繼承了Thread類就不能再繼承其他類了擴(kuò)展性差。而且這種方式把任務(wù)和線程耦合在一起不符合任務(wù)與執(zhí)行分離的設(shè)計(jì)思想。實(shí)現(xiàn)Runnable接口是更推薦的方式它把任務(wù)邏輯和線程本身解耦了。Runnable接口只有一個(gè)run方法里面寫的是任務(wù)要執(zhí)行的內(nèi)容。使用時(shí)還是需要?jiǎng)?chuàng)建Thread對(duì)象把Runnable實(shí)現(xiàn)類傳進(jìn)去調(diào)用start方法。這種方式的好處是任務(wù)類還可以繼承其他類也更符合面向接口編程的思想。到了JDK 5引入了Callable接口和Runnable相比最大的區(qū)別是Callable的call方法有返回值而且可以拋出異常。但Callable不能直接傳給Thread使用需要配合FutureTask來包裝一下。FutureTask實(shí)現(xiàn)了Runnable接口所以可以傳給Thread同時(shí)又實(shí)現(xiàn)了Future接口可以獲取異步計(jì)算結(jié)果。線程池是JDK 5同時(shí)推出的也是目前生產(chǎn)環(huán)境用的最多的方式。核心思想是復(fù)用線程避免頻繁創(chuàng)建和銷毀線程帶來的性能開銷。阿里開發(fā)手冊(cè)明確禁止使用Executors工具類創(chuàng)建線程池而是要求通過ThreadPoolExecutor的方式手動(dòng)創(chuàng)建這樣可以更明確地控制線程池的運(yùn)行規(guī)則避免資源耗盡的風(fēng)險(xiǎn)。我個(gè)人的經(jīng)驗(yàn)是面試中回答創(chuàng)建方式時(shí)不要只是干巴巴地羅列幾種方式可以主動(dòng)說一下各自的適用場(chǎng)景和優(yōu)缺點(diǎn)對(duì)比這會(huì)讓面試官覺得你是有真實(shí)項(xiàng)目經(jīng)驗(yàn)的而不是背八股。1.2 線程生命周期與狀態(tài)流轉(zhuǎn)線程的生命周期是所有線程知識(shí)的基石理解不透徹后面學(xué)什么都不順暢。Java線程在運(yùn)行過程中有六種狀態(tài)定義在Thread.State這個(gè)枚舉類里。NEW狀態(tài)是線程被創(chuàng)建但還沒調(diào)用start方法時(shí)的狀態(tài)。RUNNABLE是調(diào)用了start方法之后的狀態(tài)這里要注意Java的RUNNABLE狀態(tài)其實(shí)包含了操作系統(tǒng)層面的運(yùn)行中和就緒兩種狀態(tài)也就是線程可能正在CPU上執(zhí)行也可能在等待CPU時(shí)間片。BLOCKED是線程在等待獲取監(jiān)視器鎖也就是synchronized的鎖時(shí)的狀態(tài)比如一個(gè)線程進(jìn)入了synchronized代碼塊另一個(gè)線程也想進(jìn)入就會(huì)進(jìn)入BLOCKED狀態(tài)。WAITING是線程正在等待另一個(gè)線程執(zhí)行特定動(dòng)作時(shí)的狀態(tài)比如調(diào)用了Object.wait()、Thread.join()、LockSupport.park()都會(huì)進(jìn)入這個(gè)狀態(tài)。TIMED_WAITING是帶超時(shí)時(shí)間的等待狀態(tài)比如Thread.sleep、Object.wait(long timeout)、Thread.join(long millis)等。TERMINATED是線程執(zhí)行完run方法后的最終狀態(tài)。狀態(tài)流轉(zhuǎn)是面試的重點(diǎn)尤其容易被問到sleep和wait有什么區(qū)別這里一定要說清楚。sleep是Thread類的靜態(tài)方法調(diào)用后線程進(jìn)入TIMED_WAITING狀態(tài)但不會(huì)釋放任何鎖資源wait是Object類的方法調(diào)用后線程進(jìn)入WAITING狀態(tài)并且會(huì)釋放持有的鎖。這也是為什么wait方法必須在synchronized代碼塊中調(diào)用因?yàn)樗枰瘸钟墟i然后釋放鎖讓其他線程有機(jī)會(huì)獲取鎖。sleep則沒有這個(gè)限制任何地方都能調(diào)用。還有一個(gè)高頻考點(diǎn)是線程的start方法和run方法有什么區(qū)別很多新手會(huì)犯直接調(diào)用run方法的錯(cuò)誤。start方法會(huì)啟動(dòng)一個(gè)新線程由新線程去執(zhí)行run方法里的邏輯直接調(diào)用run方法就只是在當(dāng)前線程執(zhí)行一個(gè)普通的方法調(diào)用根本沒有創(chuàng)建新線程。判斷一個(gè)線程是否啟動(dòng)過可以看thread.getState()是否不等于NEW。關(guān)于狀態(tài)流轉(zhuǎn)我建議畫一張狀態(tài)轉(zhuǎn)換圖幫助記憶。我自己當(dāng)年學(xué)的時(shí)候把六種狀態(tài)的觸發(fā)條件和轉(zhuǎn)換關(guān)系整理成了一張表格貼在電腦旁邊天天看很快就記住了。后面排查線上問題的時(shí)候用jstack工具查看線程棧信息看到線程停在什么狀態(tài)、等在哪把鎖上這都是一眼就能看出來的基本功。2. 線程安全的核心機(jī)制synchronized與volatile線程安全問題本質(zhì)上是因?yàn)槎嗑€程同時(shí)訪問共享數(shù)據(jù)時(shí)發(fā)生了競(jìng)爭(zhēng)。Java解決線程安全的手段很多但synchronized和volatile是最基礎(chǔ)、最核心的兩個(gè)關(guān)鍵詞。面試中幾乎必問這兩個(gè)關(guān)鍵字的原理和區(qū)別所以這塊一定要深入理解。先理解什么是臨界區(qū)和競(jìng)態(tài)條件。臨界區(qū)是訪問共享資源的代碼段同一時(shí)刻只允許一個(gè)線程進(jìn)入。競(jìng)態(tài)條件是指多個(gè)線程同時(shí)讀寫共享數(shù)據(jù)時(shí)最終結(jié)果取決于線程執(zhí)行的相對(duì)時(shí)序可能導(dǎo)致數(shù)據(jù)不一致。解決競(jìng)態(tài)條件的思路就是讓臨界區(qū)的代碼原子執(zhí)行即不可分割要么全部執(zhí)行完要么不執(zhí)行。synchronized關(guān)鍵字就是Java提供的解決并發(fā)安全的經(jīng)典機(jī)制。它有三種用法修飾實(shí)例方法、修飾靜態(tài)方法、修飾代碼塊。修飾實(shí)例方法時(shí)鎖的是當(dāng)前實(shí)例對(duì)象修飾靜態(tài)方法時(shí)鎖的是類的Class對(duì)象修飾代碼塊時(shí)鎖的是括號(hào)里指定的對(duì)象。這里有一個(gè)細(xì)節(jié)很多人會(huì)搞混synchronized修飾靜態(tài)方法和修飾實(shí)例方法它們鎖的對(duì)象是不同的所以兩者之間并不會(huì)互斥。2.1 synchronized的底層實(shí)現(xiàn)與鎖升級(jí)synchronized在JDK 6之前是一把重量級(jí)鎖性能表現(xiàn)不佳因?yàn)樗牡讓右蕾囉诓僮飨到y(tǒng)的互斥量mutex線程阻塞和喚醒都需要從用戶態(tài)切換到內(nèi)核態(tài)這個(gè)切換代價(jià)很大。所以在早期很多高并發(fā)場(chǎng)景下會(huì)刻意避免使用synchronized轉(zhuǎn)而使用JDK 5推出的Lock接口。但JDK 6引入了鎖升級(jí)機(jī)制之后synchronized的性能得到了大幅提升很多場(chǎng)景下性能已經(jīng)和ReentrantLock相差無幾。鎖升級(jí)的方向是無鎖 - 偏向鎖 - 輕量級(jí)鎖 - 重量級(jí)鎖。這個(gè)升級(jí)方向是單向的不會(huì)降級(jí)。偏向鎖是鎖升級(jí)的第一級(jí)。它的設(shè)計(jì)思想是大多數(shù)情況下鎖不僅不存在多線程競(jìng)爭(zhēng)而且總是由同一個(gè)線程多次獲得。所以當(dāng)一個(gè)線程第一次訪問同步代碼塊時(shí)會(huì)在對(duì)象頭中記錄持有鎖的線程ID后續(xù)這個(gè)線程再次進(jìn)入時(shí)就不需要再做任何同步操作了。如果有其他線程來競(jìng)爭(zhēng)這把鎖偏向鎖就會(huì)撤銷升級(jí)為輕量級(jí)鎖。輕量級(jí)鎖的獲取方式是CAS自旋。多個(gè)線程在無競(jìng)爭(zhēng)的情況下交替執(zhí)行同步代碼塊時(shí)通過CAS操作嘗試把對(duì)象頭中的鎖標(biāo)記替換為自己的線程記錄。如果替換成功就獲得了鎖如果失敗說明有競(jìng)爭(zhēng)就會(huì)自旋等待。自旋是占用CPU的所以如果競(jìng)爭(zhēng)激烈、自旋次數(shù)過多就會(huì)升級(jí)為重量級(jí)鎖。JDK 6之后自旋是自適應(yīng)的JVM會(huì)根據(jù)上次自旋的結(jié)果動(dòng)態(tài)調(diào)整自旋次數(shù)。重量級(jí)鎖就是傳統(tǒng)的互斥鎖依賴操作系統(tǒng)的mutex實(shí)現(xiàn)。當(dāng)競(jìng)爭(zhēng)非常激烈時(shí)沒有獲取到鎖的線程會(huì)進(jìn)入阻塞狀態(tài)由用戶態(tài)切換到內(nèi)核態(tài)這個(gè)切換涉及上下文切換開銷很大。理解了鎖升級(jí)機(jī)制之后再回頭分析synchronized的適用場(chǎng)景就清楚了鎖競(jìng)爭(zhēng)不激烈的情況下用synchronized完全沒問題但是一旦高并發(fā)下競(jìng)爭(zhēng)激烈synchronized會(huì)膨脹為重量級(jí)鎖性能急劇下降這時(shí)候就要考慮ReentrantLock或者讀寫鎖了。2.2 volatile的可見性與有序性volatile是Java提供的最輕量級(jí)的同步機(jī)制它有兩個(gè)核心作用保證可見性和有序性但不能保證原子性。可見性是指當(dāng)一個(gè)線程修改了volatile變量的值該值會(huì)立即被刷新到主內(nèi)存中其他線程讀取該變量時(shí)會(huì)從主內(nèi)存中重新讀取最新的值而不是使用自己工作內(nèi)存中的副本。這解決的是多線程之間的數(shù)據(jù)透明問題。有序性是指volatile會(huì)禁止指令重排序。編譯器和CPU為了優(yōu)化執(zhí)行效率可能會(huì)對(duì)代碼指令進(jìn)行重排這在單線程環(huán)境下沒有問題但在多線程環(huán)境下可能導(dǎo)致意想不到的結(jié)果。volatile通過在讀寫操作前后插入內(nèi)存屏障阻止指令重排到屏障的另一側(cè)從而保證了程序執(zhí)行的順序符合編寫時(shí)的預(yù)期。但是volatile不保證原子性這也是面試中最容易考到的一個(gè)點(diǎn)。經(jīng)典的場(chǎng)景是i操作雖然i被聲明為volatile但i實(shí)際上是讀-改-寫三步操作不是一個(gè)原子操作。多個(gè)線程同時(shí)執(zhí)行i時(shí)還是可能出現(xiàn)數(shù)據(jù)覆蓋的問題。所以volatile適合修飾那些多個(gè)線程都會(huì)讀取、但只有少數(shù)線程會(huì)寫入、且寫入不依賴當(dāng)前值的場(chǎng)景典型的就是作為狀態(tài)標(biāo)志位。在并發(fā)編程中還有一個(gè)著名的happens-before原則需要了解。這個(gè)原則定義了多線程操作之間的內(nèi)存可見性規(guī)則是JMMJava內(nèi)存模型的核心內(nèi)容。happens-before規(guī)則包括程序順序規(guī)則、鎖規(guī)則、volatile變量規(guī)則、傳遞性規(guī)則等。其中volatile變量規(guī)則說的是對(duì)一個(gè)volatile變量的寫操作happens-before于后續(xù)對(duì)該變量的讀操作。理解這些規(guī)則能幫你判斷到底能不能用volatile解決當(dāng)前的問題。我面試時(shí)喜歡問一個(gè)問題synchronized和volatile有什么區(qū)別這個(gè)問題考察的是對(duì)并發(fā)基礎(chǔ)的理解深度。標(biāo)準(zhǔn)的回答應(yīng)該圍繞三方面一是volatile本質(zhì)是告訴JVM這個(gè)變量是共享且不穩(wěn)定的每次都要從主內(nèi)存中讀取synchronized則是讓多個(gè)線程互斥訪問臨界區(qū)。二是volatile只能修飾變量不能修飾方法synchronized可以修飾方法和代碼塊。三是volatile不保證原子性synchronized保證原子性volatile不會(huì)阻塞線程synchronized會(huì)讓未獲取鎖的線程阻塞。3. 線程通信wait/notify與LockSupport多線程之間除了互斥訪問共享資源還經(jīng)常需要互相協(xié)作配合。比如生產(chǎn)者-消費(fèi)者模式中消費(fèi)者要等生產(chǎn)者生產(chǎn)出數(shù)據(jù)之后才能消費(fèi)這時(shí)候就需要線程通信機(jī)制。Java中線程通信最經(jīng)典的方式是wait/notify機(jī)制使用Object類的wait、notify、notifyAll方法。這三個(gè)方法都必須在synchronized代碼塊或者synchronized方法中調(diào)用因?yàn)樗鼈儾僮鞯膶?duì)象的監(jiān)視器鎖。調(diào)用wait方法后當(dāng)前線程會(huì)釋放持有的鎖并進(jìn)入WAITING狀態(tài)直到其他線程調(diào)用同一個(gè)對(duì)象上的notify或notifyAll方法將它喚醒。這里有個(gè)非常重要的細(xì)節(jié)notify方法是隨機(jī)喚醒一個(gè)正在等待該對(duì)象鎖的線程notifyAll是喚醒所有等待的線程。如果需要精確喚醒某個(gè)特定的線程那就要用后面引入的Lock和Condition機(jī)制了。JDK 5之后引入了Lock接口和Condition接口Condition提供了await、signal、signalAll方法功能類似wait、notify、notifyAll但更加靈活。一個(gè)Lock可以創(chuàng)建多個(gè)Condition每個(gè)Condition維護(hù)一個(gè)獨(dú)立的等待隊(duì)列這樣就能實(shí)現(xiàn)精確喚醒某個(gè)或某類線程而不是像synchronized那樣只能使用一個(gè)隱式條件隊(duì)列。舉個(gè)例子在實(shí)現(xiàn)一個(gè)有界阻塞隊(duì)列時(shí)如果用synchronized實(shí)現(xiàn)只有一個(gè)等待隊(duì)列生產(chǎn)者生產(chǎn)滿時(shí)等待消費(fèi)者消費(fèi)空時(shí)等待notify時(shí)無法區(qū)分喚醒的是生產(chǎn)者還是消費(fèi)者。而有了Condition之后可以創(chuàng)建兩個(gè)ConditionnotEmpty和notFull消費(fèi)者等待notEmpty條件生產(chǎn)者等待notFull條件這樣就能精準(zhǔn)喚醒對(duì)應(yīng)類型的線程效率更高且邏輯更清晰。LockSupport是更底層的線程阻塞工具類基于Unsafe類的park和unpark方法實(shí)現(xiàn)。它的核心優(yōu)勢(shì)是不需要持有鎖就能使用且unpark可以先于park調(diào)用也就是許可機(jī)制使得線程可以先被叫醒再等待。AQS框架中大量使用了LockSupport來管理線程的阻塞與喚醒。我在實(shí)際項(xiàng)目中用Condition的場(chǎng)景還是蠻多的比如實(shí)現(xiàn)限流器、實(shí)現(xiàn)任務(wù)隊(duì)列的消費(fèi)者調(diào)度。這套機(jī)制比單純用synchronized加wait/notify要優(yōu)雅得多代碼可讀性也更好。線程通信的常見面試題還包括wait方法為什么要放在while循環(huán)中答案是為了防止虛假喚醒。有些情況下線程被喚醒時(shí)等待的條件并不一定已經(jīng)滿足可能是被其他原因喚醒的所以被喚醒后要再次檢查條件是否滿足不滿足就繼續(xù)等待。這也是《Effective Java》里面明確的建議總是使用while循環(huán)來包圍wait方法調(diào)用。3.1 生產(chǎn)者消費(fèi)者模型的兩種實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模型是線程通信最經(jīng)典的應(yīng)用場(chǎng)景面試中經(jīng)常要求手寫實(shí)現(xiàn)。我用synchronized和Lock兩種方式各自實(shí)現(xiàn)了一遍這里分享下核心代碼和思路差異。用synchronized實(shí)現(xiàn)的核心邏輯是定義一個(gè)緩沖區(qū)列表和一個(gè)最大容量生產(chǎn)者和消費(fèi)者都在synchronized代碼塊內(nèi)操作。緩沖區(qū)滿了就調(diào)用wait等待緩沖區(qū)空了也調(diào)用wait等待。每次生產(chǎn)或消費(fèi)完一個(gè)數(shù)據(jù)后都調(diào)用notifyAll喚醒其他線程。class Buffer { private final ListInteger list new ArrayList(); private final int capacity 10; public synchronized void put(int value) throws InterruptedException { while (list.size() capacity) { wait(); } list.add(value); notifyAll(); } public synchronized int take() throws InterruptedException { while (list.isEmpty()) { wait(); } int value list.remove(0); notifyAll(); return value; } }用Lock和Condition實(shí)現(xiàn)的方式類似但可以區(qū)分生產(chǎn)者和消費(fèi)者的喚醒。代碼結(jié)構(gòu)上synchronized是隱式獲取和釋放鎖Lock則要求手動(dòng)加鎖和釋放鎖必須在finally中釋放鎖避免死鎖。class Buffer { private final ReentrantLock lock new ReentrantLock(); private final Condition notFull lock.newCondition(); private final Condition notEmpty lock.newCondition(); private final ListInteger list new ArrayList(); private final int capacity 10; public void put(int value) throws InterruptedException { lock.lock(); try { while (list.size() capacity) { notFull.await(); } list.add(value); notEmpty.signal(); } finally { lock.unlock(); } } public int take() throws InterruptedException { lock.lock(); try { while (list.isEmpty()) { notEmpty.await(); } int value list.remove(0); notFull.signal(); return value; } finally { lock.unlock(); } } }這兩種實(shí)現(xiàn)的性能差異在并發(fā)量不大的時(shí)候幾乎感覺不到但Lock版本的可擴(kuò)展性明顯更好。面試時(shí)如果能同時(shí)寫出兩種實(shí)現(xiàn)并且分析出各自的特點(diǎn)這是一個(gè)加分項(xiàng)。4. 鎖的進(jìn)階ReentrantLock、讀寫鎖與AQS前面反復(fù)提到Lock接口和AQS這一節(jié)重點(diǎn)展開講。JDK 5引入的java.util.concurrent并發(fā)包是Java并發(fā)編程的里程碑而AQSAbstractQueuedSynchronizer是這個(gè)并發(fā)包的靈魂。ReentrantLock是最常用的Lock實(shí)現(xiàn)類它和synchronized相比有以下幾個(gè)核心優(yōu)勢(shì)。一是支持公平鎖和非公平鎖兩種模式synchronized只能是非公平的。公平鎖按照線程請(qǐng)求鎖的順序來獲取鎖保證先來先得但吞吐量會(huì)低一些非公平鎖允許線程插隊(duì)吞吐量高但可能出現(xiàn)線程饑餓。二是支持可中斷獲取鎖調(diào)用lockInterruptibly方法后等待鎖的過程中可以被其他線程中斷而synchronized等待鎖時(shí)是不能響應(yīng)中斷的。三是支持超時(shí)獲取鎖調(diào)用tryLock(long timeout, TimeUnit unit)方法在指定時(shí)間內(nèi)獲取不到鎖就會(huì)返回false可以避免無限期等待。四是支持多個(gè)條件變量通過newCondition可以創(chuàng)建多個(gè)Condition實(shí)例。這里說一個(gè)面試高頻題ReentrantLock和synchronized的區(qū)別是什么除了上面說的四點(diǎn)還要補(bǔ)充底層的區(qū)別synchronized是JVM層面實(shí)現(xiàn)的基于監(jiān)視器鎖ReentrantLock是JDK層面實(shí)現(xiàn)的基于AQSsynchronized在JDK 6之后有鎖升級(jí)機(jī)制ReentrantLock從誕生起就使用CAS加自旋的方式實(shí)現(xiàn)。4.1 AQS的實(shí)現(xiàn)原理AQS是Java并發(fā)包的核心抽象它維護(hù)了一個(gè)volatile int類型的state變量和一個(gè)FIFO的等待隊(duì)列。state的含義由具體的子類去定義比如在ReentrantLock中state表示獲取鎖的次數(shù)在Semaphore中state表示剩余許可證的數(shù)量在CountDownLatch中state表示還需要等待的計(jì)數(shù)個(gè)數(shù)。AQS的基本思想是當(dāng)線程請(qǐng)求資源時(shí)通過CAS嘗試將state從期望值更新為新值如果成功就表示獲取資源成功如果失敗則將該線程封裝成Node節(jié)點(diǎn)插入到等待隊(duì)列的尾部然后通過LockSupport.park阻塞自己。當(dāng)前驅(qū)節(jié)點(diǎn)的線程釋放資源時(shí)會(huì)喚醒隊(duì)列中下一個(gè)節(jié)點(diǎn)對(duì)應(yīng)的線程。這里有幾個(gè)細(xì)節(jié)值得注意等待隊(duì)列中的Node節(jié)點(diǎn)每個(gè)節(jié)點(diǎn)都保存著線程引用和等待狀態(tài)。AQS在釋放資源時(shí)會(huì)從隊(duì)列頭部開始找第一個(gè)狀態(tài)有效的節(jié)點(diǎn)來喚醒。這個(gè)喚醒過程也是需要循環(huán)判斷的因?yàn)楣?jié)點(diǎn)的等待狀態(tài)可能會(huì)有變化。ReentrantLock的加鎖過程本質(zhì)上就是通過CAS把state從0改成1。如果當(dāng)前線程已經(jīng)持有鎖了再次獲取鎖時(shí)state會(huì)繼續(xù)累加這就是可重入的含義。釋放鎖時(shí)state遞減直到state變?yōu)?鎖才真正被釋放。公平鎖和非公平鎖的區(qū)別在于非公平鎖在加鎖時(shí)會(huì)先嘗試一次CAS搶鎖搶不到再進(jìn)入等待隊(duì)列公平鎖則直接進(jìn)入等待隊(duì)列排隊(duì)。4.2 讀寫鎖與StampedLockReadWriteLock讀寫鎖是一種特殊類型的鎖它維護(hù)了一對(duì)鎖一個(gè)讀鎖和一個(gè)寫鎖。讀鎖之間可以共享多個(gè)線程可以同時(shí)持有讀鎖寫鎖是排他的一個(gè)線程持有寫鎖時(shí)其他線程既不能讀也不能寫。這種設(shè)計(jì)非常適用于讀多寫少的場(chǎng)景比如緩存系統(tǒng)、配置加載等。ReentrantReadWriteLock是ReadWriteLock的實(shí)現(xiàn)類但也存在一些問題。比如讀鎖和寫鎖之間會(huì)互相阻塞也就是所謂的寫?zhàn)囸I問題如果有大量線程在持續(xù)讀寫線程可能會(huì)長(zhǎng)時(shí)間得不到執(zhí)行。它也不是完全公平的在非公平模式下寫線程插隊(duì)的機(jī)會(huì)是有限的。JDK 8引入了StampedLock它提供了一種更先進(jìn)的鎖模型。StampedLock有三種模式寫鎖、讀鎖、樂觀讀。樂觀讀是一種完全不加鎖的讀操作它先獲取一個(gè)stamp標(biāo)記然后讀數(shù)據(jù)讀完后再次檢查stamp是否發(fā)生了變化。如果沒變說明讀的過程中沒有寫操作這次讀是可靠的如果變了則升級(jí)為普通的讀鎖重讀。樂觀讀非常適合讀多寫少的場(chǎng)景能夠大幅提升吞吐量。需要注意StampedLock不是可重入的而且不支持條件變量。使用樂觀讀時(shí)必須小心驗(yàn)證stamp的有效性這個(gè)驗(yàn)證過程要放在讀數(shù)據(jù)之后。5. 線程池參數(shù)配置與運(yùn)行機(jī)制線程池是Java并發(fā)編程中應(yīng)用最廣的組件也是面試中的重頭戲。幾乎所有的Java后端服務(wù)都離不開線程池從Tomcat處理請(qǐng)求到RPC框架的異步調(diào)用都在使用線程池。理解線程池的運(yùn)作機(jī)制不只是應(yīng)付面試更是日常開發(fā)的基本功。使用線程池的好處不需要多講降低資源消耗、提高響應(yīng)速度、提高線程的可管理性。JDK的線程池實(shí)現(xiàn)核心是ThreadPoolExecutor類它提供了非常豐富的構(gòu)造參數(shù)和靈活的擴(kuò)展點(diǎn)。面試中考察線程池時(shí)幾乎必問的問題是ThreadPoolExecutor的核心參數(shù)有哪些分別代表什么含義核心參數(shù)包括corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler。corePoolSize是核心線程數(shù)核心線程即使空閑也不會(huì)被銷毀maximumPoolSize是線程池允許的最大線程數(shù)keepAliveTime是非核心線程空閑存活時(shí)間超過這個(gè)時(shí)間就會(huì)被回收workQueue是任務(wù)隊(duì)列存儲(chǔ)等待執(zhí)行的任務(wù)threadFactory是線程工廠可以自定義線程命名等屬性handler是拒絕策略當(dāng)線程池和隊(duì)列都滿時(shí)如何處理新提交的任務(wù)。5.1 任務(wù)提交與執(zhí)行流程線程池執(zhí)行任務(wù)的流程是面試中必須掌握的。當(dāng)調(diào)用execute提交一個(gè)任務(wù)時(shí)ThreadPoolExecutor的執(zhí)行策略如下如果當(dāng)前線程數(shù)小于核心線程數(shù)corePoolSize則創(chuàng)建新線程來執(zhí)行任務(wù)如果當(dāng)前線程數(shù)大于等于核心線程數(shù)且隊(duì)列未滿則把任務(wù)放入隊(duì)列中等待執(zhí)行如果隊(duì)列已滿且當(dāng)前線程數(shù)小于最大線程數(shù)maximumPoolSize則創(chuàng)建非核心線程來執(zhí)行任務(wù)如果隊(duì)列已滿且線程數(shù)已達(dá)到最大線程數(shù)則根據(jù)拒絕策略執(zhí)行拒絕處理。這個(gè)流程可以用一句話總結(jié)先看核心線程是否夠用再看隊(duì)列是否能容納最后看最大線程數(shù)是否到頂。有一點(diǎn)要注意很多框架實(shí)際使用的線程池配置比如Dubbo這類RPC框架為了降低任務(wù)處理延遲會(huì)設(shè)置足夠大的核心線程數(shù)讓線程池不會(huì)因?yàn)殛?duì)列堆積而產(chǎn)生大量等待。這是典型的空間換時(shí)間的取舍。拒絕策略有四種實(shí)現(xiàn)分別是AbortPolicy拋出RejectedExecutionException異常阻止任務(wù)提交、CallerRunsPolicy調(diào)用提交任務(wù)的線程直接執(zhí)行被拒絕的任務(wù)、DiscardPolicy默默丟棄任務(wù)、DiscardOldestPolicy丟棄隊(duì)列中最早的任務(wù)然后嘗試重新提交。生產(chǎn)環(huán)境最常用的還是AbortPolicy和CallerRunsPolicy前者快速失敗后者能將壓力回傳給提交方起到背壓效果。如果一個(gè)系統(tǒng)對(duì)任務(wù)丟失不能接受那就要自定義拒絕策略比如把任務(wù)持久化到數(shù)據(jù)庫或消息隊(duì)列里。5.2 線程池參數(shù)配置的經(jīng)驗(yàn)公式線程池參數(shù)并沒有一個(gè)萬能的配置公式具體要結(jié)合業(yè)務(wù)場(chǎng)景來定。但從經(jīng)驗(yàn)來看可以根據(jù)任務(wù)類型是CPU密集型還是IO密集型來做初步估算。CPU密集型任務(wù)指的是計(jì)算量大、很少有IO等待的任務(wù)比如大量數(shù)學(xué)運(yùn)算、圖像渲染。這類任務(wù)的瓶頸在CPU線程數(shù)和CPU核心數(shù)相當(dāng)即可。一般配置為CPU核心數(shù)1公式是Ncpu1。加1是為了避免CPU空轉(zhuǎn)當(dāng)某個(gè)線程因?yàn)槿表摶蚱渌虮粫和r(shí)多出的線程可以頂上。IO密集型任務(wù)指的是大量時(shí)間在等待IO操作的任務(wù)比如網(wǎng)絡(luò)請(qǐng)求、數(shù)據(jù)庫讀寫、文件操作。這類任務(wù)等待時(shí)間長(zhǎng)CPU占用率低所以可以配置更多的線程。一般配置為CPU核心數(shù)的兩倍公式是2*Ncpu。更精細(xì)的估算方法是線程數(shù) CPU核心數(shù) * (1 平均等待時(shí)間 / 平均計(jì)算時(shí)間)。但這個(gè)公式對(duì)時(shí)間比的估計(jì)很難精確實(shí)踐中通常直接用2倍核數(shù)起步再通過壓測(cè)調(diào)整。拒絕策略的選擇和隊(duì)列類型也要配套考慮。比如使用有界隊(duì)列時(shí)隊(duì)列容量可以這樣估算期望的排隊(duì)等待時(shí)間乘以請(qǐng)求速率。如果平均請(qǐng)求速率為1000個(gè)每秒期望最大排隊(duì)時(shí)間為2秒那么隊(duì)列容量就可以設(shè)置為2000。當(dāng)然這只是理論參考實(shí)際還是以壓測(cè)為準(zhǔn)。我自己習(xí)慣的配置方法是先把核心線程數(shù)設(shè)置為系統(tǒng)的常駐請(qǐng)求并發(fā)數(shù)最大線程數(shù)設(shè)置為峰值并發(fā)數(shù)隊(duì)列容量設(shè)置為峰值和均值之間的緩沖量然后通過壓測(cè)逐步微調(diào)。線程池參數(shù)永遠(yuǎn)不是一次配置就完成的而是在運(yùn)行過程中持續(xù)監(jiān)控和調(diào)整的。5.3 手動(dòng)創(chuàng)建線程池的正確姿勢(shì)前文提到阿里開發(fā)手冊(cè)禁止使用Executors創(chuàng)建線程池原因是Executors提供的幾個(gè)工廠方法都有隱患。newFixedThreadPool和newSingleThreadExecutor使用了無界隊(duì)列LinkedBlockingQueue當(dāng)任務(wù)提交速度超過處理速度時(shí)隊(duì)列會(huì)無限增長(zhǎng)最終可能導(dǎo)致內(nèi)存溢出。newCachedThreadPool的最大線程數(shù)是Integer.MAX_VALUE如果任務(wù)提交過快而處理速度跟不上會(huì)創(chuàng)建大量線程耗盡系統(tǒng)資源。newScheduledThreadPool同樣存在隊(duì)列無界的問題。正確的方式是使用ThreadPoolExecutor的構(gòu)造方法手動(dòng)創(chuàng)建。下面給一個(gè)參考配置ThreadPoolExecutor executor new ThreadPoolExecutor( corePoolSize, // 核心線程數(shù) maximumPoolSize, // 最大線程數(shù) keepAliveTime, // 非核心線程空閑存活時(shí)間 TimeUnit.SECONDS, // 時(shí)間單位 new ArrayBlockingQueue(queueCapacity), // 有界任務(wù)隊(duì)列 new ThreadFactory() { private final AtomicInteger counter new AtomicInteger(); Override public Thread newThread(Runnable r) { Thread thread new Thread(r, business-thread- counter.incrementAndGet()); thread.setDaemon(false); return thread; } }, new ThreadPoolExecutor.AbortPolicy() // 拒絕策略 );給線程命名是一個(gè)容易被忽視但很重要的細(xì)節(jié)。線上排查問題時(shí)如果線程名都是有業(yè)務(wù)含義的比如order-service-thread-1、mq-consumer-thread-2jstack輸出一眼就能看出是哪個(gè)業(yè)務(wù)模塊的線程出了問題。如果所有線程都叫pool-1-thread-1排查效率會(huì)低很多。線程池還需要關(guān)注動(dòng)態(tài)調(diào)整。ThreadPoolExecutor提供了setCorePoolSize和setMaximumPoolSize方法可以在運(yùn)行期調(diào)整參數(shù)。比較常見的做法是通過監(jiān)控系統(tǒng)度量指標(biāo)根據(jù)當(dāng)前的隊(duì)列長(zhǎng)度和活躍線程數(shù)動(dòng)態(tài)調(diào)整線程池參數(shù)來應(yīng)對(duì)流量波動(dòng)。這在秒殺、大促這類場(chǎng)景特別有用。最后必須強(qiáng)調(diào)線程池在Spring容器中要作為單例Bean管理不要在每個(gè)業(yè)務(wù)方法里new一個(gè)線程池。我見過有同事在循環(huán)內(nèi)創(chuàng)建線程池直接把內(nèi)存打爆了。線程池是重資源必須復(fù)用量級(jí)實(shí)例。6. ThreadLocal與內(nèi)存泄漏陷阱ThreadLocal是一個(gè)很有意思的類它提供線程局部變量每個(gè)線程都有自己獨(dú)立的變量副本互不干擾。ThreadLocal的典型應(yīng)用場(chǎng)景包括存儲(chǔ)用戶會(huì)話信息、數(shù)據(jù)庫連接管理、SimpleDateFormat日期格式化工具的線程安全替換方案。ThreadLocal的原理說復(fù)雜也復(fù)雜說簡(jiǎn)單也簡(jiǎn)單。每個(gè)Thread對(duì)象內(nèi)部都有一個(gè)ThreadLocalMap這個(gè)Map的key是ThreadLocal對(duì)象本身的弱引用value是線程持有的變量值。當(dāng)線程訪問ThreadLocal時(shí)ThreadLocal內(nèi)部類會(huì)先從當(dāng)前線程中獲取ThreadLocalMap然后以自身為key去查找對(duì)應(yīng)的value。這里就引出了ThreadLocal最著名的內(nèi)存泄漏問題。ThreadLocalMap的key是弱引用WeakReferencevalue是強(qiáng)引用。當(dāng)外部沒有對(duì)ThreadLocal的強(qiáng)引用時(shí)GC回收時(shí)就會(huì)把key清掉但value仍然是強(qiáng)引用鏈Thread - ThreadLocalMap - Entry - value。如果線程生命周期很長(zhǎng)而value一直不被清除就會(huì)造成內(nèi)存泄漏。規(guī)避這個(gè)問題的方法已經(jīng)成為一個(gè)共識(shí)使用完ThreadLocal后必須調(diào)用remove方法清除。尤其是在線程池場(chǎng)景下線程復(fù)用次數(shù)很多如果不顯式remove同一個(gè)線程處理不同請(qǐng)求時(shí)可能會(huì)讀取到上一個(gè)請(qǐng)求殘留的ThreadLocal值造成數(shù)據(jù)混亂。這個(gè)坑非常隱蔽線上偶發(fā)出現(xiàn)用戶串號(hào)這類問題很多就是ThreadLocal沒清理導(dǎo)致的。我習(xí)慣在finally塊里調(diào)用remove保證異常情況下也能清除。示例代碼如下try { threadLocal.set(userInfo); // 業(yè)務(wù)邏輯 } finally { threadLocal.remove(); }另外要提醒的是不要在靜態(tài)方法中跨線程使用ThreadLocal也不要把ThreadLocal的value設(shè)計(jì)成可變的共享對(duì)象。ThreadLocal解決的是線程間的變量隔離問題如果value本身是被多個(gè)線程共享的引用類型那線程隔離的效果就大打折扣了。6.1 子線程如何繼承父線程的ThreadLocal如果我們希望主線程設(shè)置的ThreadLocal值能被子線程讀取到直接使用ThreadLocal是做不到的因?yàn)樽泳€程是獨(dú)立的新線程有自己的ThreadLocalMap。這時(shí)候可以使用InheritableThreadLocal。InheritableThreadLocal繼承了ThreadLocal它在線程創(chuàng)建時(shí)會(huì)把父線程的ThreadLocalMap中的值復(fù)制一份到子線程中。這樣子在子線程中就能讀取到父線程設(shè)置的值了。但是這里也有坑如果主線程在創(chuàng)建子線程之后修改了ThreadLocal的值子線程中的副本并不會(huì)自動(dòng)更新。它只是創(chuàng)建時(shí)的一份快照之后兩者互不影響。如果需要實(shí)現(xiàn)父子線程間的全量傳遞比如鏈路追蹤需要把traceId傳遞到異步線程池中那就需要更強(qiáng)大的方案了。目前業(yè)內(nèi)常用的做法是使用TransmittableThreadLocalTTL這是阿里開源的一個(gè)庫能在線程池場(chǎng)景下實(shí)現(xiàn)上下文的無損傳遞。TTL會(huì)在任務(wù)提交時(shí)捕獲當(dāng)前線程的ThreadLocal值并在任務(wù)執(zhí)行時(shí)重新設(shè)置到執(zhí)行線程中執(zhí)行完再恢復(fù)原值。這個(gè)工具在分布式鏈路追蹤和異步并發(fā)場(chǎng)景中很有用如果簡(jiǎn)歷上寫到了相關(guān)項(xiàng)目面試時(shí)提到TTL是一個(gè)不錯(cuò)的加分項(xiàng)。7. 并發(fā)工具類CountDownLatch、CyclicBarrier、SemaphoreJDK 5在并發(fā)包中提供了幾個(gè)非常實(shí)用的同步工具類CountDownLatch、CyclicBarrier、Semaphore、Exchanger。它們基于AQS實(shí)現(xiàn)面試中考察概率很高尤其喜歡考CountDownLatch和CyclicBarrier的區(qū)別。CountDownLatch是一個(gè)倒計(jì)時(shí)器它允許一個(gè)或多個(gè)線程等待其他線程完成一組操作后再繼續(xù)執(zhí)行。典型場(chǎng)景是主線程啟動(dòng)多個(gè)子線程并行執(zhí)行任務(wù)等所有子任務(wù)都完成后主線程再匯總結(jié)果。使用方法是先new CountDownLatch(n)指定計(jì)數(shù)數(shù)量每個(gè)子線程執(zhí)行完任務(wù)后調(diào)用countDown方法將計(jì)數(shù)減一主線程調(diào)用await方法阻塞等待直到計(jì)數(shù)變?yōu)?。CountDownLatch的計(jì)數(shù)是單向的減到0之后就無法重置了所以它只能使用一次。如果需要重復(fù)使用的場(chǎng)景應(yīng)該用CyclicBarrier。CyclicBarrier是循環(huán)屏障它允許多個(gè)線程在某個(gè)屏障點(diǎn)互相等待直到所有線程都到達(dá)該屏障點(diǎn)才繼續(xù)執(zhí)行。和CountDownLatch相比CyclicBarrier是所有線程互相等待而不是一個(gè)線程等待其他線程。它的計(jì)數(shù)可以重置所以可以循環(huán)使用。CyclicBarrier還支持一個(gè)可選的Runnable參數(shù)當(dāng)所有線程到達(dá)屏障點(diǎn)時(shí)會(huì)先執(zhí)行這個(gè)Runnable中的代碼。Semaphore是信號(hào)量它維護(hù)一組許可證線程在執(zhí)行前必須先acquire獲取許可證執(zhí)行完release歸還許可證。Semaphore常用于控制同時(shí)訪問特定資源的線程數(shù)比如連接池的連接數(shù)限制、限流控制。公平模式的Semaphore能保證先獲取許可證的線程先執(zhí)行避免饑餓問題。這三種工具類的適用場(chǎng)景很容易混淆我整理一個(gè)對(duì)比幫助記憶工具類核心用途使用次數(shù)等待關(guān)系CountDownLatch一個(gè)線程等待多個(gè)線程完成只能使用一次單向等待CyclicBarrier多個(gè)線程互相等待到達(dá)屏障可循環(huán)使用互相等待Semaphore控制同時(shí)執(zhí)行任務(wù)的最大線程數(shù)可重復(fù)使用獲取/釋放許可證它們?nèi)齻€(gè)在AQS中的實(shí)現(xiàn)方式也不同。CountDownLatch和Semaphore都是通過state字段來記錄計(jì)數(shù)或許可證數(shù)量獲取資源就是CAS遞減state釋放資源就是CAS遞增state。CyclicBarrier的實(shí)現(xiàn)更復(fù)雜一些它內(nèi)部使用了一個(gè)ReentrantLock和Condition來協(xié)調(diào)所有線程的等待和喚醒。7.1 實(shí)際項(xiàng)目中如何選用并發(fā)工具我做一個(gè)具體案例來演示這三個(gè)工具的實(shí)際選型思路。假設(shè)有一個(gè)數(shù)據(jù)統(tǒng)計(jì)任務(wù)要把10份數(shù)據(jù)文件分別統(tǒng)計(jì)再合并匯總出總結(jié)果。這個(gè)問題用CountDownLatch就很合適主線程開著10個(gè)子線程分別統(tǒng)計(jì)每個(gè)統(tǒng)計(jì)完countDown一次主線程await后做合并匯總。用CyclicBarrier也可以做但語義上不如CountDownLatch直接。再假設(shè)有這樣一個(gè)場(chǎng)景一個(gè)小組里的5個(gè)成員需要同時(shí)開始進(jìn)行一個(gè)事務(wù)流程的各階段處理每個(gè)成員處理完自己的本階段工作后需要等所有成員都完成當(dāng)前階段才能進(jìn)入下一階段。這個(gè)場(chǎng)景就是CyclicBarrier的經(jīng)典用例每輪階段結(jié)束就自動(dòng)進(jìn)入下一輪循環(huán)使用。而控制某個(gè)服務(wù)的最大并發(fā)調(diào)用數(shù)比如限定對(duì)第三方接口的調(diào)用并發(fā)不超過20則會(huì)用Semaphore。每次調(diào)用前acquire調(diào)用完release超出的請(qǐng)求就會(huì)阻塞等待。在真實(shí)的高并發(fā)項(xiàng)目中這三個(gè)工具經(jīng)常組合使用。比如用Semaphore限流用CountDownLatch做任務(wù)編排用CyclicBarrier做分階段并行計(jì)算。理解了每個(gè)工具的設(shè)計(jì)目標(biāo)和適用場(chǎng)景寫起來就自然順暢。8. 多線程問題排查與實(shí)戰(zhàn)技巧理論講了這么多最終還是要落到實(shí)戰(zhàn)。多線程開發(fā)中代碼層面的問題往往是隱蔽且難以復(fù)現(xiàn)的死鎖、線程泄漏、CPU飆高、內(nèi)存溢出每一類都讓人頭疼。這節(jié)分享一下我在實(shí)際項(xiàng)目中排查多線程問題的思路和方法。死鎖是最經(jīng)典的多線程問題。產(chǎn)生死鎖的四個(gè)條件是互斥條件、持有并等待條件、不可剝奪條件、循環(huán)等待條件。排查死鎖時(shí)最快的方式是使用jstack命令獲取當(dāng)前Java進(jìn)程的線程快照它會(huì)自動(dòng)檢測(cè)死鎖并打印出死鎖的線程和鎖的持有情況。先通過jps找到Java進(jìn)程的PID然后執(zhí)行jstack PID輸出信息中如果包含F(xiàn)ound one Java-level deadlock這樣的字樣就說明死鎖了。隨后信息中會(huì)詳細(xì)展示兩個(gè)線程分別持有什么鎖、在等待什么鎖。根據(jù)這些信息就能定位到是哪段代碼導(dǎo)致的死鎖。線上遇到CPU飆高的問題排查思路是先通過top -H -p PID找到CPU占用率最高的線程ID把它轉(zhuǎn)成十六進(jìn)制然后jstack PID | grep -A 20 nid0x十六進(jìn)制值就能定位到具體線程的堆棧。如果堆棧停留在線程池的任務(wù)執(zhí)行方法上那大概率是某個(gè)業(yè)務(wù)方法出現(xiàn)了死循環(huán)或者大量的無效計(jì)算。對(duì)于線程池線程數(shù)量異常增長(zhǎng)的問題多半是任務(wù)隊(duì)列容量設(shè)置不合理或者拒絕策略配置不當(dāng)。優(yōu)先檢查ThreadPoolExecutor的四個(gè)關(guān)鍵指標(biāo)當(dāng)前活躍線程數(shù)、核心線程數(shù)、最大線程數(shù)、隊(duì)列剩余容量。可以通過暴露metrics接口來定期采集這些狀態(tài)配合監(jiān)控告警在問題擴(kuò)大前及時(shí)介入。我曾經(jīng)排查過一個(gè)典型的線程泄漏問題線上服務(wù)運(yùn)行幾天后線程數(shù)線性增長(zhǎng)最終內(nèi)存溢出。jstack后發(fā)現(xiàn)大量線程阻塞在數(shù)據(jù)庫連接獲取處。究其原因是某個(gè)線程池中的任務(wù)里調(diào)用了數(shù)據(jù)庫操作但因?yàn)槭聞?wù)配置錯(cuò)誤導(dǎo)致連接沒有釋放后續(xù)任務(wù)全部積壓在等待連接的隊(duì)列中線程池不斷創(chuàng)建新的線程來承接新任務(wù)。最終定位到的是連接泄漏問題而不是線程池配置問題。所以排查線程問題時(shí)要跳出線程本身去看它依賴的資源和下游系統(tǒng)。多線程的調(diào)試也很特殊斷點(diǎn)調(diào)試多線程時(shí)往往會(huì)改變線程的執(zhí)行時(shí)序原來能復(fù)現(xiàn)的并發(fā)Bug可能一下子就不出現(xiàn)了。我建議多用日志來輔助排查在關(guān)鍵節(jié)點(diǎn)打印線程名、時(shí)間戳、關(guān)鍵數(shù)據(jù)狀態(tài)。給線程起好名字在這里就顯得特別重要了打印出來的日志里如果能直接看到是哪個(gè)業(yè)務(wù)的線程在活動(dòng)排查效率能提升一大截。還有一個(gè)小技巧在開發(fā)階段可以通過設(shè)置JVM參數(shù)-XX:PrintConcurrentLocks來打印并發(fā)鎖的信息結(jié)合jstack使用能更清楚地看到鎖的競(jìng)爭(zhēng)情況。另外如果項(xiàng)目用了Caffeine或者Redisson這類第三方庫它們?cè)谌罩纠镆矔?huì)有關(guān)鍵線索比如阻塞隊(duì)列深度、鎖等待時(shí)間等。9. 面試答題技巧與高頻八股速查最后這部分我結(jié)合自己面試和被面的經(jīng)驗(yàn)整理一份高頻Java線程八股的快問快答順便聊一下怎么答才能從海量候選人中脫穎而出。先說答題思路。八股文的答案大多有個(gè)標(biāo)準(zhǔn)范式但面試官真正想看的是你有沒有自己的理解。所以回答任何概念題我建議按照是什么-為什么-怎么用-有什么坑的四段式結(jié)構(gòu)來展開。比如被問到synchronized鎖升級(jí)不要只背偏向鎖、輕量級(jí)鎖、重量級(jí)鎖三個(gè)名詞而要說清楚為什么需要鎖升級(jí)、JDK 6之前性能差的原因是什么、升級(jí)條件是什么、什么場(chǎng)景下會(huì)出現(xiàn)什么問題。這樣的回答會(huì)讓面試官覺得你是真的用過在真實(shí)項(xiàng)目中踩過坑有思考深度。常見問題速查如下線程創(chuàng)建方式有幾種四種繼承Thread、實(shí)現(xiàn)Runnable、實(shí)現(xiàn)Callable配合FutureTask、線程池。線程有哪些狀態(tài)六種NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED。注意RUNNABLE是Java層概念實(shí)際可能處于運(yùn)行中或者等待CPU調(diào)度。sleep和wait區(qū)別sleep不釋放鎖wait釋放鎖sleep是Thread方法wait是Object方法sleep需要指定時(shí)間wait可以不指定也可以指定時(shí)間sleep用于暫停執(zhí)行wait用于線程間通信。synchronized和ReentrantLock區(qū)別是否自動(dòng)釋放鎖、是否可重入都可重入、是否支持公平鎖、是否可中斷、是否支持多個(gè)條件變量、底層實(shí)現(xiàn)JVM層面 vs JDK層面。volatile和synchronized的區(qū)別volatile不保證原子性、只能修飾變量、不會(huì)阻塞線程synchronized保證原子性、可修飾方法和代碼塊、未獲取鎖的線程會(huì)阻塞。ThreadLocal內(nèi)存泄漏的解決方案使用完調(diào)用remove或者在ThreadLocal的Entry中通過弱引用來輔助回收。線程池的拒絕策略有哪些AbortPolicy拋異常、CallerRunsPolicy調(diào)用者執(zhí)行、DiscardPolicy丟棄、DiscardOldestPolicy丟棄最老的。生產(chǎn)環(huán)境最常用AbortPolicy和CallerRunsPolicy。CountDownLatch和CyclicBarrier區(qū)別方向不同CountDownLatch是一個(gè)/多個(gè)線程等待其他線程CyclicBarrier是多個(gè)線程互相等待CountDownLatch只能使用一次CyclicBarrier可以循環(huán)使用CountDownLatch基于AQSCyclicBarrier基于ReentrantLock和Condition。CAS的優(yōu)缺點(diǎn)優(yōu)點(diǎn)是非阻塞、無需鎖和上下文切換缺點(diǎn)是只能保證一個(gè)變量的原子操作、循環(huán)時(shí)間長(zhǎng)開銷大、存在ABA問題。ABA問題可以通過AtomicStampedReference加版本號(hào)解決。什么是線程安全多個(gè)線程訪問共享數(shù)據(jù)時(shí)無論線程如何交替執(zhí)行最終結(jié)果都符合預(yù)期且不產(chǎn)生數(shù)據(jù)破壞。有一個(gè)問題值得特別說一下為什么阿里規(guī)范強(qiáng)調(diào)不用Executors創(chuàng)建線程池除了前面說的無界隊(duì)列和最大線程數(shù)問題還有一個(gè)隱性問題Executors里創(chuàng)建的線程工廠基本都是默認(rèn)的線程名毫無辨識(shí)度出問題排查起來很麻煩。使用自定義ThreadPoolExecutor加自定義ThreadFactory是最佳的實(shí)踐路徑。最后的最后想跟準(zhǔn)備面試的朋友說一句線程八股的知識(shí)點(diǎn)再多歸根結(jié)底是幫助你建立對(duì)并發(fā)編程的完整認(rèn)知框架。不要只是死記硬背建議把文中的代碼都動(dòng)手跑一遍改一改參數(shù)觀察現(xiàn)象遇到問題再回頭看理論印象會(huì)深刻得多。并發(fā)編程是一門實(shí)踐性很強(qiáng)的學(xué)問理論只是地圖真正踏過一遍坑才能成為自己手頭的能力。
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
欧美久久伊人| 超碰九九| 色爱国产| 亚洲成a人片在线观看中文!!!| 91精品国产一区三一| 久久国产视频专区一二三| 亚洲国产一级精品毛一级精品看免费视频| 夜夜嗨一区二区三区直播内容| 麻豆天美电影一区二区| 久久久久国产精品喷潮免费观看臀 | 色色五月婷| 不卡中文字幕aⅴ在线| 色哟哟av网址| 狠插 制服 自拍| 欧美一级做a爰片免费视频| a片久久久久久久久久久久 | 日本十八禁免费看污网站| 欧美日韩中文字幕不卡| 97视频在线免费播放| 国产精品九9| 大香蕉啪啪啪| www.色综合| 玖玖爱免费观看视频| 成人精品在线免费视频| 麻豆国产97在线| 97超碰日韩| 亚洲成人帖图| 密臀国产在线| 久久九九热| 成人欧美日超碰| 艳美熟妇先锋一二三区| 97超碰国产亚洲精品资源| 国产久久久久久久久一区二区 | 成人黄页| 亚洲成人ab| 亚州欧美在线| 成人性交午夜免费片| 人妻无码一区二区三区久久99| 亚洲男人天堂2016| 欧美97视频| 天天摸天天舔天天操| 超碰97网址| 乱老女人一区二区视频| 成人在线视频网| av三级电影在线播放| 精彩久久中文| 麻豆天天躁天天揉揉AV| 清纯唯美激情| 99999精品| 国产精品白丝www| 国产精品动态一区二区三区四四| yazhouzaixian| 99re在线精品78| 欧美高清在线| 国产一区二区在线看| 中文字幕青青草| 99国产女人| 亚洲天天操| 天天噜| 老熟女91| 一级岛国大片| 国产18精品亚洲精品| 天天做天天爱| 青青草啪啪网| 清纯唯美综合亚洲| 人妻色偷色噜| **一级毛片国产| 夂久色| 18精品一区| 国产熟女二区| 亚洲91网| 日韩欧美字幕亚洲一区二区| 国产欧美伊人| 青青草这里只有精品| 精品午夜福利| 99视频只有精品| 密臀在线免费观看| 97网色| 一级二级三级黑人无码| 超碰成人免费| 好舒服视频| 啊啊啊好大好深| 在线免费观看日韩一区| 天天舔天天 | 久久成人国产| 亚码激情| 国产在线激情| 欧美性爱三区二区| 亚洲精品国产精品乱码不卡| 蜜臀久久久99久久久久 | 岛国黄片网站| 久艹伊人精品综合在线| 丝袜足交视频| 大香蕉久久| 东京成人一区| 91欧美亚洲| 久操网无码在线| 日韩啪啪啪啪啪| 97超碰免费人人性爱| 九九热三级片| 九九伊人网| 一区二区视频你懂的| 91成人无码| 日本国产高清色www视频在线| av中文在线| 夜夜做夜夜爽精品视频| 懂色av色欲av蜜臀av| 青青青操| 东北毛片| 日韩国产品视频中文字| 日本乱人伦片中文三区| 97超碰天天爱天天爱| 综合欧美亚洲| 中文伊人大香蕉视频| 精品十八在线观看| 自偷自拍的亚洲视频| 噜噜噜亚洲精品| 国产一区二区三区白丝| 色九月综合| 91福利网在线观看| 玖玖爱综合| 欧美激情综合| ai欧美亚洲小说| 日日操免费视频| 国产精品久久久久久夜夜夜| 亚洲一区二区三区欧美日韩| 青青草国产欧美非洲黑人| 天天天天干| 蜜臀久久99精品久久久久| 99热这里只有精品9| 日韩精品资源| 99re69综合| 亚洲AV麻豆Aⅴ无码电影一| 亚洲情色婷婷五月天| 国产精品人妻无码久久久老鸭窝| 麻豆AV96熟妇人妻| 成人aⅴ一区二区三区| 亚洲图片偷拍欧美| 熟女精品一区二区三区| 亲子敌伦对白在线播放| 2000亚洲男人天堂| 国产版a级片直播在线| 亚春色色| 男女激情中文字幕| 亚洲少妇中文字幕网址| 人人妻人人爽一区二区三区| 国产av白丝| 边做饭边操逼逼| 99re这里| 欧美欲色| 色色色色网站| 搞中出久久| 爱丝福利| 99自拍B亚洲| 日韩欧美成人综合在线| 91丨人妻丨国产丨丝袜| 欧美 日韩 另类 亚洲| 日韩亚洲中文字幕在线| 91精品网站| 国产美女激情| 这里只有精品久久| 99精品欧美一区二区三区桃色| 18精品一二区| 丰满搜索结果 -第18页- 久久高清无码| 高清成年美女黄网站免费大全| 99福利社| 国产91专区| 天天看综合网| 国产亚洲综合欧美一区| 乱伦一区二区三区‘| 97精品一区二区视频在线观看| 欧美在线官网| 亚洲精品日韩国产欧美| 中文字幕日韩精品久久| 欧美色乱| 91精品操美女| 久久一本大香蕉 | 91激情国产| 久9久| 日韩丝袜二区| 91人妻最真实刺激绿帽| 午夜美女福利视频| 亚洲男人天堂网站| 曰本特级特黄特色黄色A级网站高清在线免费看 | 粉嫩av在线一区二区| 一中国女人毛片水真多| 78操B| 亚洲精品蜜桃久久久久久久| 国产天天骚| 99精品无码| 尤物国产一区在线观看| 日本午夜操逼| 国产三级多多影院2022国产AA一级毛片无码 | 亚洲暴力强奸AV| 欧美亚洲中文| 久久久人妻| 精品人妻一区二区三区四区| 中文字幕精品亚洲熟女| 大香蕉色欲AV| 亚洲精品白丝| 国产吹潮女在线观看| 蜜屁Av| 国产成人AV麻豆| 91爱综合| 日本不卡三级网在线播放| 亚洲激情AV| 免费A V在线| 女人喷水视频在线观看| 乱伦av.com| 日逼国产| 久久婷婷伊人| 一区二区三区 丝袜 高跟 美腿| 丁香五月天激情| 午夜色婷婷| 发朗少妇买婬全视频中文| 91久久久久久| AV丝袜少妇| 久久久久网站-538在线视频-欧美永久乱码| 女色视频社区| 丰满搜索结果 -第18页- 久久高清无码| 精品一区二区三区蜜桃臀赵总 | 日韩ab网 | 国产视频第二页| 国内毛片四区| 亚洲婷婷丁香在线| 宅男影院久久久,99| 国产又色又粗又黄又爽| 免费看黄视频亚洲网站| HEYZO高无码国产精品227| 久草福利在线资源站| 激情综合久久| 欧美色图亚州激情| 天堂网亚洲区手机版| 麻豆美女丝袜人妻中文| 无码高清国产AV| 一区二区娱乐网站| 亚洲不卡不卡中文字幕不卡 | 国产性爱在线视频一区二区| 强奸a片网| 久久最新免费视频23| 九九拍拍精品视频在线播放 | 五月天丁香婷婷综合网站| 无码少妇精品一区二区60岁老人| 91国产精品在线看| 青青伊人加勒比海| 狠狠久久手机视频精品| 把腿张开老子CAO烂你| 五月天婷婷综合网| 亚洲无限观看| 亚洲一区二区在线观看91| 亚欧性爱无码| 亚洲 综合 欧美| 久久久久久久久久久久黄色 | 97天天插| 黄色大片免费在线| 一区中文字幕二区日韩| 精品二区久久| 成人性爱av| 国产欧美一区激情交| 午夜啊啊啊| 999国产精品999久久久久久| 少妇一区二区三区精选| 一起草AV| 日本性一区| 亚洲最新Av| 九久9精品| 欧美亚洲AN| 野狼福利社区| 亚洲成av人片色午夜乱码| 校园春色综合色| 日本男人天堂| 国产67194| 欧美大战久久久伊人| 久一区久久蜜桃| 国产1769在线| 97精品视频在线播放| 操啊国产| 亚洲人在线成线成人| 2017,超碰| 精品人妻一区二区视频| 青青草色情网站视频| 欧美综合网在线| 精品久久人妻成人网| 色 亚洲 91| 久久久久久69国产一区二区| 欧美在线色图| 乱伦一区二区三区‘| 久久伊人网视频一区二区三区| 水滴偷拍| 99re6久热只有精品6在线直播| 一卡二卡在线播放| 日本天天色| 久久久月天| 高清国产av无码| 日韩av电影网站| 东北丰满熟女国产一区| 美女诱惑在线一区| 中国zzijzzijzzwww精品| 骚逼一区二区| 国产精品无套内谢| 97超碰公开| 成人日韩欧美| 丝袜综合网| 天美精品av| 欧美性色网| 日韩人体偷拍| 久久亚洲欧美中文字幕国语| 男人精品天堂一区| 色色色欧美| 好吊色综合| 欧美内射少妇| 日本一级二级三级网站| 97精品免费视频网站| 好吊妞转入那个网| 人妻81p| 在线洲亚线| 欧苏综合色综合| 自拍偷拍第26| 91超碰在线观看| 伊色综合天堂色97| 精品中文字幕一区二区| 51一区二区三区| 五月丁香色婷婷| 日本不卡一区二区| 97超碰总站| 亚洲va综合va国产va中文| 白丝AV| 国产精品视频| 亚州色图第三区| 蜜乳中文字幕a在线| 夜夜操一区二区| 十八禁视频网站| 久久男人的天堂| 久久精品免视看国产成人﹣蜜臀av一区. 久久精品免视看国产成人,蜜臀av一区 | 后入式福利| 熟女一区二区| 男人的天堂不卡一区二区| a片自拍直播视频| 久久久草草精品| 99这里有精品| 国产福利第一视频| 麻花传媒免费网站在线观看| 国产日本一区二区三区蜜臀在线观看| 丝袜天堂网| 亚洲情色1区| 国产精品自拍欧美在线| AAAAAAAAA黄片| 久热一区二区| 欧美第五页| 91骚妇| 97人人干| 天天色播亚洲综合网站| 日韩免费三级黄片电影| 亚洲天堂男人天堂网| 久久久精品一区二区| 伊人青青一区成人视频在线观看区| 91快色色色色色| 日B操| 男人久久天堂| 我要色综合网站| 久久久久久久久久精| 中文字幕丝袜美腿| 亚洲精品 大香蕉| 伊人色综合网电影| 国产福利小视频高清在线观看| 免费A片三p视频| 花花AV导航| 骚熟女AV网| 啊啊啊啊啊啊啊啊啊在线观看| 无码91| 亚洲人妻一区二区三区| 巨爆乳肉感一区二区三区竹菊影视| 日韩中文字幕精品一区在线| 婷婷av在线中文字幕| 欧美+日产+中文| 变态另类专区| 日日夜夜免费| 一起草三级AV电影在线观看| 国产福利视频精品视频| 一二三四视频中文字幕在线看| 蜜臀无码视频在线观看| 久久久久亚洲三级电影| 岛国激情视频在线观看| 欧美日韩国产高清在线一二三区| 小视频国产| 天天操天天干一区二区 | 超碰成人最新最好看| 日本免费中文字幕在线| 亚洲成人免费中文字幕| 午夜电影在线观看无码专区| 中文字幕狠狠玩| 亚洲精品影视老司机| 国产亚洲精品农村妇女| 天堂8在线新版官网| 欧美疯狂做爰xxxx| 婷婷月色| 69精品人人人人| 97免费免费视频网| 九九九九九九九九九九精品视频| 77国产精品| 夫妻AV网站| 天堂综合网| yw尤物av无码点击进入麻豆| 日韩操逼HD| 日本国产高清色www视频在线| 国产aⅴ无码片毛片一级网站| 成人三一级一片aaa| 丁香六月啪| 99热超碰| 精品一区二区三区四区外站| 香蕉人欧美综合| 色婷婷亚洲婷婷| 涩五月婷婷| 欧美男女午夜啪啪| αⅴ天堂| 99自拍B亚洲| 中文字幕在线观看AV| 男人天堂黄片| 99re热有精品视频国产| 草莓精品视频| 亚 欧 美 综合| 日韩人妻精品中文字幕| 91熟女网| 这里只有精品视频在线观看麻豆| 97精品综合| 欧美一区二区传媒| 亚洲高清91| 亚洲成aⅴ人片不卡无码| 一级黄色性爱A级片| 色色色热| 久久人妻无码毛片A片麻豆| 国产精品夜夜| 亚洲情色中文字幕一区| 国产自产91区13区| 久久精品一区一起草| 日本一级特级毛片视频| av天堂5| 啊a一区在线| 97欧美色综合| 中文字幕,人妻,日韩| 丁香六月婷婷久久综合| 日产成人久久| 人人看人人插| 天美av在线观看| 午夜福利一区二区三区四区五区色婷婷| 亚洲熟女综合网| 欧美国产伊人久久久久| 蜜臀AV成人精品蜜臀| 东京太热男人的天堂久久久| 无码免费精品高清| 1024午夜激情男人的天堂| 网站A V在线| 高清无码网址| 亚洲做性| 综合久久欧美| 狠狠爱夜夜干| 日韩国产乱子伦App| 人妻精品4K4K4K4K4| 91熟女丨老女人| 大香蕉乱伦视频网| 熟女91网| 蜜乳av首页| 997色在线| 无码av永久免费专区网站| 久久久久一本一区二区青青蜜月| 97超碰站| 欧洲乱码一区二区| 中文字幕日韩精品久久| 青青操在线亚洲视频观看欧美在线 | 国产一二三福利视频网| 99视频自拍| 正宗无毛一线天嫩逼| 第一高清av中文字幕| 亚洲AV在线资源| 色色香蕉| 色婷婷一区二区三区久久午夜成人不| 国产三级中文有码在线视频| 国产精品3| 最新日产中文在线麻豆| 国产精品一区二区麻豆| 精品人妻伦一二三区久久| 人妻久久| 青青操97| 亚洲第一黄色av网站 | 日本日逼视频网| 日本在线999| 久久极品一区二区| 精品久久久久久AV无码| 国产十八禁视频| 日本www操操操| rivers-china.com| 日本不卡三级网在线播放| 麻豆综合一区av| 一区二区三区无卡视频在线观看| 把腿张开老子CAO烂你| 骚货操死你| 九色 人妻 大香蕉| 九色精品视频导航1| 很狠操| 志村玲子视频一区二区| 手机午夜电影神马久久| 91插B网站| 中文字幕91综合| 少妇人妻好深太紧了vr91| 9 1超碰九色| http://qxhbdz.com| 黄色片,com| 男人天堂2030| 色爽——AV| 六月婷激情福利天堂69| 欧美人妻一区| 色吧5亚洲| 国产AV线| 97色欧州| 大香交伊人网| 国产精品久久久久中文字幕| 一级性爱网| 欧美91久久久久| 大香蕉免| 深夜啪啪啪视频免费| 国产亚洲日韩在线三区黑人| 97啪啪| 夜夜春夜夜操| 综合av影片| 深夜操逼网| 亚洲精品第一| 一级片在线观看高清无码| 啊啊啊久久| 亭亭在线资源| 秋霞午夜视频一区二区| 啊啊啊用力在线观看| 静品嫩模一区二区| 狠狠色狠狠色狠狠五月| 18禁无码永久免费无限制| 久久精品国产亚洲av水密被窝| 日本男人插女人的逼黄色| 欧美日韩国产中文超碰| 亚洲精品99| 激情五月天丁香社区| 啪啪啪东京| 乱伦熟女论坛| 风月影院十八禁| 国产激情在线| 97在线播放| 欧美日韩另类字幕中文| 国产亚洲色婷婷99精品91| 日韩紧密久久| 天操天操夜操夜月操月年年操| 99久热| 久草视频分类在线| 精品国产久热在线观看| 亚洲精品一区二区三区在线播放| 在线A日本| 先锋激情∨在线视频播放| 国产精品不卡一区二区电影| 久久精品国产Aⅴ| 久草午夜| 家庭乱伦国产精品| 狠狠色伊人亚洲综合网站色| 久久天天艹| 国产精品亚洲无码| 嗯啊抽插大香蕉网页| 无码 黑人一区二区三区| 国产精品久久天天干| 国产精品视频91久久| 中文字幕一区二区三区字幕| 久久欲| 亚洲国产精品9999在线观看| 久草视频观看视频在线| 婷婷丁香五月天亚洲天堂网| 91干熟女| 红杏大香蕉| 日本精品人妻少妇一区二区| 美女的肌被草喷水视频| 欧美少妇高潮久久91| 香蕉av一区二区三区| 在线播放中文字幕| 91亚洲人| 精品国产无码中文| 欧美特大黄一级片片免费| 五月天综合在线| 亚洲AV无码天美传媒一区| 国产精品久久久视频| 日韩钢筋无码高清啾啾啾| 330dv亚洲成年视频网| 久久九九热| 97视频在线播放| 日韩中文字幕精品一区在线| 99精品成人免费看| 亚洲另类久操网| 男人天堂综合| 91熟女丨老女人| 久久亚州精品成人Av无| 中文久久爆乳| 亚洲男人天堂网久久| AV久日| 超碰色综合| 亚欧无码在线| 青娱乐亚洲热| 白嫩白嫩的午夜九久久久久久久久久久久成人剧场 | 青青草视频在线观看一区二区| 久操大香蕉超碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰 | 91少妇香蕉久久精品| 一本大道青青| 欧美一级黄片视频在线| 日韩一级二级| 男人的天堂久久狠| 日本精品一级二级三级| 国模精品一区二区三区苹果色戒| 日韩AV一区二区三区三州三州| 欧美96交| 日韩一级特黄av毛片| 久久秀这里有精品| 91日韩网站| 亚洲色图欧美色图日韩色图| 蜜臀AV一区二区三区激情综合| 久久夜精品一区二区三区| 男人的午夜天堂| 日韩精品一区二区三区色欲| 欧美日动态视频| 天堂无码| 大香蕉操久久| 色欲天香天天综合网-成年人三级片网站-欧美乱妇狂野-日韩国产专区-久久久久久 | 亚州操操穴网| 九久9精品| 欧美成人一区二区三区在线播放| 青青草色情网站视频| 97干97色| 亚洲91少妇| 精品无人区麻豆乱码1区2区图片| 日本不卡高清视频| 屌妞视频久久久久久久久久久久| 91成人18| 欧美少妇熟女| 久久超碰com| 日日夜夜狠狠| 加勒比综合88| 性爱视频久久| 97超碰9| 这里只有精品视频在线| 精品人妻一区二区三区四区| 中文字幕 国产区| 国产人妻精品一区二区三区秋霞 | 水澄无码AV| 精品一级| 午夜精品久久久久久久男人的天堂 | 亚洲中文一区二区三区| 1024手机看片欧美日韩| 无码逼| 国产精品3| 欧美人人AAA| 中文字幕av片| 99精品久久| 欧美少妇人妻| 欧美黑人与女人91~| 黄色大片免费在线| 91色堂| 人人看人人摸人人色| 亚洲熟女乱综合一区二区在线-...亚洲国产日韩欧美一区二区三区,久久久久久精 | 日本人妻中文字幕精品| 日本一天色道久久久精品视频| 欧美性生活男人的天堂| 亚洲综合图色在线| 中国女人内射6XXXXX| 少好三P| 九九AV| 91欧洲国产成人久久精品网站| 二区熟妇韩日| 人人插人人摸人人| 99国产女人| 亚洲一二三精品久久网| 先锋激情∨在线视频播放| 91久久国外网| 男人天堂2019亚洲| 74成人在线| 久久华人网| 精品久久一区二区三区四区五区| 秋霞网无码| 国产精品久久久久久9999| 色99在线| 国产传媒午夜理伦精品| 激情婷婷黑人91| 人妻久热在线| 日本一区二区三区四区免费观看| www欧美91| 天天干天天日天天射黄色片| 成人av动漫在线观看| 男人天堂欧美| 69丨亚洲丨精品丨入口免费播放| 一二三四免费视频| 超碰在线香蕉| 伊人影院日本| 久久久久96| 在线人妻熟女一区二区三区四区五区| 亚洲欧洲精品视频发布| 色综合91好| 欧洲亚洲人人爽爽视频| 欧美第一页性| 欧美特大黄一级片片免费| 天天影视色香欲综合网小说| 久久女女| 色www精品视频在线观看| 碰碰在线视频| ?亚洲伊人伊成久久人综合网| 大香蕉一级黄色片久久| 国产青青综合伊人| 亚洲www91| 青青草密桃在线播放| 男人的天堂一区三区| 精品丝袜无码一区二区三APP| 国产又粗又长视频| 天美传媒av一区二区| 中文乱码99| 超碰人人妻| 91精品国产高清久久久久久,亚洲成人| 9色国产精品一区粉嫩 | 综合色啪| 免费观看的黄色的网站| 老外又粗又长一晚做五次| 亚洲一二三四区| 超碰天天去日穴| 91视频综合在线| 伊人一区二区三区| 日韩/97| 精品四五区| 大香蕉亚洲中文| 九九RE视频在线精品| 亚洲欧综合另类无码一区| 日韩综合成人免费视频| 日本国产亚洲一区在线观看| 97天天日| 97资源久久| 易易A毛视频| 国产又粗又长又大的视频| 丰满人妻一区| 亚州九九九精品视频| 91五月天| 美女丝袜激情小说| 超碰这里有精品| 中文字幕精品亚洲熟女| 激情内射| 青青草在线视频播放器| 欧美综合亚洲| 精品夜夜澡人妻无码AV| 日本不卡一二区| 高清无码人妻久久久一区二区三区aⅴ| 色97欧美| 亚洲加勒比| 综合伊人网12色| 无码外流操逼视频| 精品人体无圣光凹凸| 国产亚洲中文不卡二区| 欧美自拍偷拍免费观看| 欧美做爰无码A片视频| 丁香五月性爱| 婷婷成人久久久精品| 亚洲欧美九九九| 亚洲限制级| asc国产精品| 男人天堂新| 国产又黄又粗又猛大片| 国产亚洲精品久久久久小| 日本日逼高清| www.人人cao| 人妻少妇精品一区二区三区| 精品人妻一区二区免费蜜桃| 久久人妇| 亚州性色| 在线无码视频| 成人av动漫在线观看| 亚州情色j区| 天堂在线一区二区| 久久精品国产97欧美精品亚洲| 999精品乱码| 久久久久免费看少妇A片特黄| 亚洲日韩美女中文字幕乱| 日本岛国黄色网址| 好吊色一区| 天天综合欧美黑人| 69XX一中文字幕人妻91| 亚洲一区二区三区欧美日韩| 天美av在线观看| 啊嗯嗯啊好大好爽| 亚洲精品九九九| 奇米狠999| 精品人妻二区三区| 97爱啪| 国产午夜福利专区综合| 久草视频分类在线| 久久九七| 九九九九九九九九九国产精品 | 在线A日本| 久热69九色熟妇97| 91美女高潮| AA级电影三区| 大香樵伊人网| 日韩有码回春沙龙第一页| 日本黄大片在线观看视频| 97综合在线| 夜精品久无码| 亚洲一区二区三区春色| 丁香九月激情| 看看日B真人视频| 影音先锋日本乱伦| 日韩素人无码一区二区三区三州| 亚洲日本天堂| 精品人妻1区| 蜜臀精品1区2区| 狼人狠干| 99久久9| 熟女熟妇伦久久影院毛片一区二区| 天天看精品动漫视频一区| 成人av免费观看| 果冻传媒一区二区三区| 一类av片在线看| 午夜性| 福利视频香蕉免费一区二区在线| 99热9| 国产精品一区在线播放| 免费A V在线播放| 操逼999| 日韩操逼HD| 亚洲AV不卡在线观看尤物| 午夜啪| 中文有码第五页| 天天草天天日| 黑丝少妇麻豆| 蜜臀一区二区三区在线| 小草精彩毛片| 97爱| 黄色成品网站| 思思视频免费看网站| 日本熟人妻中文字幕在线|...久久国产精品-国产精品_日本一区二区三区中文字幕 | 亚洲暴力强奸AV| 学生妹天天看| 久久精品国产72国产精品福利| 日本九九久久99| 国产精品极品美女视频| 亚洲自拍欧美色综合| 人人妻人射| 亚洲亚洲亚洲天堂天堂| 无码国产精品午夜不卡(| 美女爽到高潮91| 久久婷婷五月综合| 欧美黑人极品高潮喷吹熟女黑人性暴力日韩在线欧美极品一区二区 | 久久綜合很很很| 伊人精品久久网站| 校园春色欧美| 开心五月婷婷激情| 欧美天天干| av在线浏览| 91碰超| 91色射| 荡小穴在线观看| 亚欧毛片基地国产毛片基地| 老司机午夜福利视频一区二区| 久久精品店| 大香蕉狠狠爱| 国产农村妇女精品1区二区| 亚洲图片色图欧美另类| 好吊爽好吊爽在线视频,中文字幕精品一区二区日本,国产良妇出轨视频在线观看, | 99久久99久久综合| 亚洲欧美日韩激情不卡| 口爆欧美91| 丰满少妇乱子伦精品无| 中文字幕AV中出| 激情图片伦理国产一区二区日韩| 日逼逼免费看| 色97欧美| 婷婷色香| 日本3级一区二区免费| 婷婷综合伊人一区| 超碰97最新人妻| 国内毛片无码一级毛片| 国产1024在线播放| 人澡逼| 久久9久9久99久9久9| 日逼国产| 九九九久久久| 熟女91网| 97干色天堂| 日本韩欧美在线播放a| 久久AV无码AV| 久久久精品九| 久久有码| 黄色网址久久精品欧美喷水| 丰满人妻无码一区二区三区| 青娱乐啪啪视频| 亚洲伊人久久精品影院| 天天日B狠狠操| 亚洲操逼无码| 日韩 国产 欧美自拍| 欧美春色| 久久综合久色欧美综合狠狠 | 精品无码一区二区三区色欲| 亚洲欧美天| 日本不卡二三区| 欧美1727免费观看视频| 欧美色性爱| 内射老妇BBWX0C0CK| 激情小说激情视频| 久久久久久久久国产| 有码免费观看| 国产 日韩 欧美 人妻 熟女 中文 69人妻精品一区二区绯色 | 99日精品欧美国产| 亚洲精品无码成人久久久99| 亚洲国产另类在线中文| 精品日韩产品在线,日韩在线不卡视频,欧美日韩免费专区/久, | 欧美 亚洲 另类 综合| 午夜激情床戏激情| 五月婷婷综合激情| 日本 欧美 国产一区| 26uuu成人影片| 熟妇人妻一区二区三区| 亚洲色图欧美色18直播在线| 日韩成人综合网| 99性爱在线观看| 亚洲欧洲日本精品中文a∨| 亚洲精品人体| 五月天久久人妻| 国产精品白丝AV| 熟女91网| 日韩丨制服丨中文|在线| 国产乱码精品久久久久久| 69AV女优男人的天堂| 国产精品青青草| 中文字幕二区日韩天堂| 亚洲激情综合| 99热这里只有精品9| 国产高潮AA片免费看| 国产精选三级在线观看| 日韩一区二区三区四区五区| 97人人操人人摸人人爱| 欧美强奸乱能| 91精品伊人久久久大香线蕉91| 人妻系列无码专区中文有码| 亚洲av影音先锋| 国产女生在线| 熟女视频久久| 在线只有精品| 欧美日韩国产中文超碰| 精品一区96| 亚洲精品 超碰| 欧美日韩亚洲天堂网| 亚洲男人天堂2016| 欧美国产操逼| 偷拍导航视频网站| 综合第一页| 青娱乐休闲视频在线观看| 中日韩免费看男女操逼大全| 毛片久久| 亚洲欧美综合区自拍另类| 亚洲高清无码在线桃色| 国产高清无码一区二区三区四区皇冠| 极品极品色影院| 视频二区美腿丝袜制服人妻欧美| 艳美熟妇先锋一二三区| 伊人久久大香线综合无码| 18禁久极品美女久久哦哟呀!| 男人的天堂无码| 大香久久| 久草精品国产99| 乱伦图av| 天天插天天射| 少妇与黑人高潮在线| 熟女网站最新| 无套后入双马尾| 国产毛片片精品天天看视频| 人妻丰满熟妇一区二区三| 色yeye成人免费视频| 六月丁香五月婷婷| 欧美综合色站| 人澡逼| 淫荡网址| 伊人久操| 91老司机在线视频免费观看 | 91丨人妻丨国产丨丝袜| 国产一区二区三区视频在线看| 男人的天堂一区三区| 禁止观看美女黄| 视频二区熟女人妻| 狠狠干91| 91 亚洲 欧美 日韩 国产 综合| 亚洲,欧美,春色,另类| 97超碰久| 91亚洲欧洲| www国产天美久久久| 久久久精品国产亚洲伊人| 91爱看| 国产成人在线观看网址| 国产三级中文有码在线视频| 婷婷色一区| 97在线欧| 老熟女搡BBBB搡BBBB视频| 99综合视频| 欧美色图 人妻| 中文字幕乱亚洲美女精品一区| 思思热国产在线视频| 婷婷色一区| 精品熟妇视频一区二区| 人人 操人人 操人人| 五月天婷婷综合网| 久久久91福利姬| 欧美日韩*字幕一区| 日韩一区二区精品视频| 免费国产| 黑丝自慰喷水网站| 天堂国产AV| 青青草中文字幕| 91色久| 无码九九| 欧美黄片免费在线观看视频| 啊嗯好大视频在线观看| 东京热综合久久一区二区| 亚洲午夜福利视频| 亚洲色悠悠久久88| 国产视频一区二区三区在线免费观看| 920日本午夜免费| 理论久久婷婷网8| 亚洲 欧美 手机在线观看| 吉川爱美亚洲二区在线| 久草精品国产99| 天天干2019| 蜜臀久久99精品久久久久| 99操逼| 91美女视频直播| 日韩黄色成人性爱| 欧美亚洲色的图| 91精品伊人久久久大香线蕉91| 欧美78| 亚欧成人综合影院| 色网在线| 国产日产精品久久快鸭的功能介绍| 青青草亚洲一区| 中文字幕在线免费观看2| 欧插网站| 黄色成人网久久久久久| 肥臀熟女福利视频一区二区| 久久久久97| 少妇毛片久久| 内射小黄片| 久久99999| 久久毛卡| 青青草华人在线欧美在线| 爱av免费| 国产丝袜啪啪| 人人乐大香蕉| 欧美日韩大香蕉| 亚洲美女 晚间男人天堂| 性在久久久久久| 亚洲综人| 男人的天堂不卡一区二区 | 91天天综合网,天天综合网| 免费日韩黄片| 日日干夜夜欢| 超碰在线国产| 欧美色图亚洲激情| 97综合国产精品高潮久久| 黄色视频60分钟| 欧美最大综合网| 爱射综合| 富女玩鸭子一级毛片| 欧美72网页| 久久精品国产72国产精品福利| 婷婷九月丁香| 偷拍 精品另类 凸凹了四区| 青娱乐淫乱1314| 国产精品熟妇一区二区三| 日本操BAV| 色吧91| 久久精品人妻一区二区| 日本99久久| 熟女乱3伦999| 加勒比综合a∨| 亚洲综合97中文网| 二男一女成人A片| 嗯嗯不要 视频| 黄总AV色图| 免费精品福利在线观看| 97免费视频在线观看| 97爱b| 国产11页| 你想操日本小逼吗| 久9精品| 久久久九九九九| 丁香五月AV| 秋霞久久亚洲精品成人| 成人国产二区三区在线,男女精品。| 在线综合 亚洲 欧美中文字幕 | 久久久精品视频欧州站| 亚洲天堂人妻一区二区| 国产91精品福利在线| 色网色网色网色网色网色| 久久偷偷色综合蜜桃| 精品人人| 九九RE视频在线精品| 狠狠操官网| 啊啊啊啊好多水| 亚洲天堂电影网| 射欧美综合| 99精彩视频| 免费伦费视频在线观看| 偷拍精品一区二区三区| 精品9999| 天美传媒Av在线| 18一区二区三区| 色五月婷婷色| 日韩不卡在线一区二区| 亚洲成人黄色在线观看| 男人天堂2030| 色综合 加勒比| 日韩av色图| 美女高潮视频91| 亚州色交| 伊人99热| 亚洲成A∨人影院在线欢看| 另类TS人妖一区二区三区| 中文字幕乱亚洲美女精品一区| 久久女人视频| 亚洲天堂美臀在线| 色91综合网| 亚洲中文制服诱惑| 日韩人妻精品久久久久| 综合欧美日本三级| 97人人操人人摸人人爱| 国产日韩手机视频在线| 亚洲综合欧美| 97国产人人| 啪啪自拍九九综合| 精品国产乱码久久久久久免费| 超碰97久久观看| 试看福利| 日日夜夜草草草| 中文字幕人妻色偷偷久久皮 | 日韩啪啪视频| 国产搭汕a级片| 麻豆一区二区三区在线看| 亚洲激情欧美色图| 台湾佬中文娱乐网久久久久久久久久com| 97视频7| 亚洲综合99999| 国精综合一二三区影视| 欧美色图成人网一区二区| 75大香蕉| 国精综合一二三区影视| 亚爽爽爽爽爽爽爽爽| 国产乱码精品久久久久久 | 亚洲色图亚洲无码强奸乱伦| 激情视屏国产乱伦强奸| 精品一区二区人妖| 人妻熟女av国产网站| 成人AV在线电影| 青草视频在线看看看看看看看看看| 在线只有精品| 91久久精品国产| 欧美天堂日韩三级国产传媒| 91久久堂| 日本黄色XXX| 国产久久天堂资源| 男女无套 免费网站|