成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

在JDK 5.0中使用靈活的線程鎖定機(jī)制

開(kāi)發(fā) 后端
線程和并發(fā)性并不是什么新內(nèi)容,但是Java語(yǔ)言設(shè)計(jì)中的創(chuàng)新之一就是,它是第一個(gè)直接把跨平臺(tái)線程模型和正規(guī)的內(nèi)存模型集成到語(yǔ)言中的主流語(yǔ)言。

JDK 5.0為開(kāi)發(fā)人員開(kāi)發(fā)高性能的并發(fā)應(yīng)用程序提供了一些很有效的新選擇。例如,java.util.concurrent.lock 中的類 ReentrantLock 被作為Java 語(yǔ)言中synchronized 功能的替代,它具有相同的內(nèi)存語(yǔ)義、相同的鎖定,但在爭(zhēng)用條件下卻有更好的性能,此外,它還有synchronized 沒(méi)有提供的其他特性。這是否意味著我們應(yīng)當(dāng)忘記synchronized ,轉(zhuǎn)而只用 ReentrantLock 呢?并發(fā)性專家 Brian Goetz 剛從他的夏季休假中返回,他將為我們提供答案。

多線程和并發(fā)性并不是什么新內(nèi)容,但是Java 語(yǔ)言設(shè)計(jì)中的創(chuàng)新之一就是,它是第一個(gè)直接把跨平臺(tái)線程模型和正規(guī)的內(nèi)存模型集成到語(yǔ)言中的主流語(yǔ)言。核心類庫(kù)包含一個(gè)Thread 類,可以用它來(lái)構(gòu)建、啟動(dòng)和操縱線程,Java 語(yǔ)言包括了跨線程傳達(dá)并發(fā)性約束的構(gòu)造 —— synchronized 和 volatile 。在簡(jiǎn)化與平臺(tái)無(wú)關(guān)的并發(fā)類的開(kāi)發(fā)的同時(shí),它決沒(méi)有使并發(fā)類的編寫工作變得更繁瑣,只是使它變得更容易了。

synchronized 快速回顧

把代碼塊聲明為 synchronized,有兩個(gè)重要后果,通常是指該代碼具有 原子性(atomicity)和 可見(jiàn)性(visibility)。原子性意味著一個(gè)線程一次只能執(zhí)行由一個(gè)指定監(jiān)控對(duì)象(lock)保護(hù)的代碼,從而防止多個(gè)線程在更新共享狀態(tài)時(shí)相互沖突。可見(jiàn)性則更為微妙;它要對(duì)付內(nèi)存緩存和編譯器優(yōu)化的各種反常行為。一般來(lái)說(shuō),線程以某種不必讓其他線程立即可以看到的方式(不管這些線程在寄存器中、在處理器特定的緩存中,還是通過(guò)指令重排或者其他編譯器優(yōu)化),不受緩存變量值的約束,但是如果開(kāi)發(fā)人員使用了同步,如下面的代碼所示,那么運(yùn)行庫(kù)將確保某一線程對(duì)變量所做的更新先于對(duì)現(xiàn)有 synchronized 塊所進(jìn)行的更新,當(dāng)進(jìn)入由同一監(jiān)控器(lock)保護(hù)的另一個(gè) synchronized 塊時(shí),將立刻可以看到這些對(duì)變量所做的更新。類似的規(guī)則也存在于 volatile 變量上。

synchronized (lockObject) {
 // update object state
} 

所以,實(shí)現(xiàn)同步操作需要考慮安全更新多個(gè)共享變量所需的一切,不能有爭(zhēng)用條件,不能破壞數(shù)據(jù)(假設(shè)同步的邊界位置正確),而且要保證正確同步的其他線程可以看到這些變量的最新值。通過(guò)定義一個(gè)清晰的、跨平臺(tái)的內(nèi)存模型(該模型在 JDK 5.0 中做了修改,改正了原來(lái)定義中的某些錯(cuò)誤),通過(guò)遵守下面這個(gè)簡(jiǎn)單規(guī)則,構(gòu)建“一次編寫,隨處運(yùn)行”的并發(fā)類是有可能的:

不論什么時(shí)候,只要您將編寫的變量接下來(lái)可能被另一個(gè)線程讀取,或者您將讀取的變量最后是被另一個(gè)線程寫入的,那么您必須進(jìn)行同步。
不過(guò)現(xiàn)在好了一點(diǎn),在最近的 JVM 中,沒(méi)有爭(zhēng)用的同步(一個(gè)線程擁有鎖的時(shí)候,沒(méi)有其他線程企圖獲得鎖)的性能成本還是很低的。(也不總是這樣;早期 JVM 中的同步還沒(méi)有優(yōu)化,所以讓很多人都這樣認(rèn)為,但是現(xiàn)在這變成了一種誤解,人們認(rèn)為不管是不是爭(zhēng)用,同步都有很高的性能成本。)

對(duì)synchronized 的改進(jìn)

如此看來(lái)同步相當(dāng)好了,是么?那么為什么 JSR 166 小組花了這么多時(shí)間來(lái)開(kāi)發(fā) java.util.concurrent.lock 框架呢?答案很簡(jiǎn)單-同步是不錯(cuò),但它并不完美。它有一些功能性的限制 —— 它無(wú)法中斷一個(gè)正在等候獲得鎖的線程,也無(wú)法通過(guò)投票得到鎖,如果不想等下去,也就沒(méi)法得到鎖。同步還要求鎖的釋放只能在與獲得鎖所在的堆棧幀相同的堆棧幀中進(jìn)行,多數(shù)情況下,這沒(méi)問(wèn)題(而且與異常處理交互得很好),但是,確實(shí)存在一些非塊結(jié)構(gòu)的鎖定更合適的情況。

ReentrantLock 類

java.util.concurrent.lock 中的 Lock 框架是鎖定的一個(gè)抽象,它允許把鎖定的實(shí)現(xiàn)作為 Java 類,而不是作為語(yǔ)言的特性來(lái)實(shí)現(xiàn)。這就為 Lock 的多種實(shí)現(xiàn)留下了空間,各種實(shí)現(xiàn)可能有不同的調(diào)度算法、性能特性或者鎖定語(yǔ)義。 ReentrantLock 類實(shí)現(xiàn)了 Lock ,它擁有與 synchronized 相同的并發(fā)性和內(nèi)存語(yǔ)義,但是添加了類似鎖投票、定時(shí)鎖等候和可中斷鎖等候的一些特性。此外,它還提供了在激烈爭(zhēng)用情況下更佳的性能。(換句話說(shuō),當(dāng)許多線程都想訪問(wèn)共享資源時(shí),JVM 可以花更少的時(shí)候來(lái)調(diào)度線程,把更多時(shí)間用在執(zhí)行線程上。)

reentrant 鎖意味著什么呢?簡(jiǎn)單來(lái)說(shuō),它有一個(gè)與鎖相關(guān)的獲取計(jì)數(shù)器,如果擁有鎖的某個(gè)線程再次得到鎖,那么獲取計(jì)數(shù)器就加1,然后鎖需要被釋放兩次才能獲得真正釋放。這模仿了 synchronized 的語(yǔ)義;如果線程進(jìn)入由線程已經(jīng)擁有的監(jiān)控器保護(hù)的 synchronized 塊,就允許線程繼續(xù)進(jìn)行,當(dāng)線程退出第二個(gè)(或者后續(xù)) synchronized 塊的時(shí)候,不釋放鎖,只有線程退出它進(jìn)入的監(jiān)控器保護(hù)的第一個(gè) synchronized 塊時(shí),才釋放鎖。

在查看清單 1 中的代碼示例時(shí),可以看到 Lock 和 synchronized 有一點(diǎn)明顯的區(qū)別 —— lock 必須在 finally 塊中釋放。否則,如果受保護(hù)的代碼將拋出異常,鎖就有可能永遠(yuǎn)得不到釋放!這一點(diǎn)區(qū)別看起來(lái)可能沒(méi)什么,但是實(shí)際上,它極為重要。忘記在 finally 塊中釋放鎖,可能會(huì)在程序中留下一個(gè)定時(shí)炸彈,當(dāng)有一天炸彈爆炸時(shí),您要花費(fèi)很大力氣才有找到源頭在哪。而使用同步,JVM 將確保鎖會(huì)獲得自動(dòng)釋放。

清單1:用 ReentrantLock 保護(hù)代碼塊

Lock lock = new ReentrantLock();
lock.lock();
try {
 // update object state
}
finally {
 lock.unlock();
}

除此之外,與目前的 synchronized 實(shí)現(xiàn)相比,爭(zhēng)用下的 ReentrantLock 實(shí)現(xiàn)更具可伸縮性。(在未來(lái)的 JVM 版本中,synchronized 的爭(zhēng)用性能很有可能會(huì)獲得提高。)這意味著當(dāng)許多線程都在爭(zhēng)用同一個(gè)鎖時(shí),使用 ReentrantLock 的總體開(kāi)支通常要比 synchronized 少得多。#p#

比較ReentrantLock和synchronized的可伸縮性

Tim Peierls 用一個(gè)簡(jiǎn)單的線性全等偽隨機(jī)數(shù)生成器(PRNG)構(gòu)建了一個(gè)簡(jiǎn)單的評(píng)測(cè),用它來(lái)測(cè)量 synchronized 和 Lock 之間相對(duì)的可伸縮性。這個(gè)示例很好,因?yàn)槊看握{(diào)用 nextRandom() 時(shí),PRNG 都確實(shí)在做一些工作,所以這個(gè)基準(zhǔn)程序?qū)嶋H上是在測(cè)量一個(gè)合理的、真實(shí)的 synchronized 和 Lock 應(yīng)用程序,而不是測(cè)試純粹紙上談兵或者什么也不做的代碼(就像許多所謂的基準(zhǔn)程序一樣。)

在這個(gè)基準(zhǔn)程序中,有一個(gè) PseudoRandom 的接口,它只有一個(gè)方法 nextRandom(int bound) 。該接口與 java.util.Random 類的功能非常類似。因?yàn)樵谏上乱粋€(gè)隨機(jī)數(shù)時(shí),PRNG 用最新生成的數(shù)字作為輸入,而且把最后生成的數(shù)字作為一個(gè)實(shí)例變量來(lái)維護(hù),其重點(diǎn)在于讓更新這個(gè)狀態(tài)的代碼段不被其他線程搶占,所以我要用某種形式的鎖定來(lái)確保這一點(diǎn)。( java.util.Random 類也可以做到這點(diǎn)。)我們?yōu)?PseudoRandom 構(gòu)建了兩個(gè)實(shí)現(xiàn);一個(gè)使用 syncronized,另一個(gè)使用 java.util.concurrent.ReentrantLock 。驅(qū)動(dòng)程序生成了大量線程,每個(gè)線程都瘋狂地爭(zhēng)奪時(shí)間片,然后計(jì)算不同版本每秒能執(zhí)行多少輪。圖 1 和 圖 2 總結(jié)了不同線程數(shù)量的結(jié)果。這個(gè)評(píng)測(cè)并不完美,而且只在兩個(gè)系統(tǒng)上運(yùn)行了(一個(gè)是雙 Xeon 運(yùn)行超線程 Linux,另一個(gè)是單處理器 Windows 系統(tǒng)),但是,應(yīng)當(dāng)足以表現(xiàn) synchronized 與 ReentrantLock 相比所具有的伸縮性優(yōu)勢(shì)了。


圖 1. synchronized和Lock的吞吐率,單CPU


圖 2. synchronized和Lock的吞吐率(標(biāo)準(zhǔn)化之后),4個(gè) CPU

圖1和圖2中的圖表以每秒調(diào)用數(shù)為單位顯示了吞吐率,把不同的實(shí)現(xiàn)調(diào)整到 1 線程 synchronized 的情況。每個(gè)實(shí)現(xiàn)都相對(duì)迅速地集中在某個(gè)穩(wěn)定狀態(tài)的吞吐率上,該狀態(tài)通常要求處理器得到充分利用,把大多數(shù)的處理器時(shí)間都花在處理實(shí)際工作(計(jì)算機(jī)隨機(jī)數(shù))上,只有小部分時(shí)間花在了線程調(diào)度開(kāi)支上。您會(huì)注意到,synchronized 版本在處理任何類型的爭(zhēng)用時(shí),表現(xiàn)都相當(dāng)差,而 Lock 版本在調(diào)度的開(kāi)支上花的時(shí)間相當(dāng)少,從而為更高的吞吐率留下空間,實(shí)現(xiàn)了更有效的 CPU 利用。

條件變量

根類 Object 包含某些特殊的方法,用來(lái)在線程的 wait() 、 notify() 和 notifyAll() 之間進(jìn)行通信。這些是高級(jí)的并發(fā)性特性,許多開(kāi)發(fā)人員從來(lái)沒(méi)有用過(guò)它們 —— 這可能是件好事,因?yàn)樗鼈兿喈?dāng)微妙,很容易使用不當(dāng)。幸運(yùn)的是,隨著 JDK 5.0 中引入 java.util.concurrent ,開(kāi)發(fā)人員幾乎更加沒(méi)有什么地方需要使用這些方法了。

通知與鎖定之間有一個(gè)交互 —— 為了在對(duì)象上 wait 或 notify ,您必須持有該對(duì)象的鎖。就像 Lock 是同步的概括一樣, Lock 框架包含了對(duì) wait 和 notify 的概括,這個(gè)概括叫作 條件(Condition) 。 Lock 對(duì)象則充當(dāng)綁定到這個(gè)鎖的條件變量的工廠對(duì)象,與標(biāo)準(zhǔn)的 wait 和 notify 方法不同,對(duì)于指定的 Lock ,可以有不止一個(gè)條件變量與它關(guān)聯(lián)。這樣就簡(jiǎn)化了許多并發(fā)算法的開(kāi)發(fā)。例如, 條件(Condition) 的 Javadoc 顯示了一個(gè)有界緩沖區(qū)實(shí)現(xiàn)的示例,該示例使用了兩個(gè)條件變量,“not full”和“not empty”,它比每個(gè) lock 只用一個(gè) wait 設(shè)置的實(shí)現(xiàn)方式可讀性要好一些(而且更有效)。 Condition 的方法與 wait 、 notify 和 notifyAll 方法類似,分別命名為 await 、 signal 和 signalAll ,因?yàn)樗鼈儾荒芨采w Object 上的對(duì)應(yīng)方法。

這不公平

如果查看 Javadoc,您會(huì)看到,ReentrantLock 構(gòu)造器的一個(gè)參數(shù)是 boolean值,它允許您選擇想要一個(gè) 公平(fair)鎖,還是一個(gè) 不公平(unfair)鎖。公平鎖使線程按照請(qǐng)求鎖的順序依次獲得鎖;而不公平鎖則允許討價(jià)還價(jià),在這種情況下,線程有時(shí)可以比先請(qǐng)求鎖的其他線程先得到鎖。

為什么我們不讓所有的鎖都公平呢?畢竟,公平是好事,不公平是不好的,不是嗎?(當(dāng)孩子們想要一個(gè)決定時(shí),總會(huì)叫嚷“這不公平”。我們認(rèn)為公平非常重要,孩子們也知道。)在現(xiàn)實(shí)中,公平保證了鎖是非常健壯的鎖,有很大的性能成本。要確保公平所需要的記帳(bookkeeping)和同步,就意味著被爭(zhēng)奪的公平鎖要比不公平鎖的吞吐率更低。作為默認(rèn)設(shè)置,應(yīng)當(dāng)把公平設(shè)置為 false ,除非公平對(duì)您的算法至關(guān)重要,需要嚴(yán)格按照線程排隊(duì)的順序?qū)ζ溥M(jìn)行服務(wù)。

那么同步又如何呢??jī)?nèi)置的監(jiān)控器鎖是公平的嗎?答案令許多人感到大吃一驚,它們是不公平的,而且永遠(yuǎn)都是不公平的。但是沒(méi)有人抱怨過(guò)線程饑渴,因?yàn)?JVM 保證了所有線程最終都會(huì)得到它們所等候的鎖。確保統(tǒng)計(jì)上的公平性,對(duì)多數(shù)情況來(lái)說(shuō),這就已經(jīng)足夠了,而這花費(fèi)的成本則要比絕對(duì)的公平保證的低得多。所以,默認(rèn)情況下 ReentrantLock 是“不公平”的,這一事實(shí)只是把同步中一直是事件的東西表面化而已。如果您在同步的時(shí)候并不介意這一點(diǎn),那么在 ReentrantLock 時(shí)也不必為它擔(dān)心。

圖3和圖4包含與圖1和圖2相同的數(shù)據(jù),只是添加了一個(gè)數(shù)據(jù)集,用來(lái)進(jìn)行隨機(jī)數(shù)基準(zhǔn)檢測(cè),這次檢測(cè)使用了公平鎖,而不是默認(rèn)的協(xié)商鎖。正如您能看到的,公平是有代價(jià)的。如果您需要公平,就必須付出代價(jià),但是請(qǐng)不要把它作為您的默認(rèn)選擇。


圖 3. 使用4個(gè)CPU時(shí)的同步、協(xié)商鎖和公平鎖的相對(duì)吞吐率


圖 4. 使用1個(gè)CPU時(shí)的同步、協(xié)商和公平鎖的相對(duì)吞吐率

處處都好?

看起來(lái) ReentrantLock 無(wú)論在哪方面都比 synchronized 好 —— 所有 synchronized 能做的,它都能做,它擁有與 synchronized 相同的內(nèi)存和并發(fā)性語(yǔ)義,還擁有 synchronized 所沒(méi)有的特性,在負(fù)荷下還擁有更好的性能。那么,我們是不是應(yīng)當(dāng)忘記 synchronized ,不再把它當(dāng)作已經(jīng)已經(jīng)得到優(yōu)化的好主意呢?或者甚至用 ReentrantLock 重寫我們現(xiàn)有的 synchronized 代碼?實(shí)際上,幾本 Java 編程方面介紹性的書籍在它們多線程的章節(jié)中就采用了這種方法,完全用 Lock 來(lái)做示例,只把 synchronized 當(dāng)作歷史。但我覺(jué)得這是把好事做得太過(guò)了。

還不要拋棄synchronized

雖然 ReentrantLock 是個(gè)非常動(dòng)人的實(shí)現(xiàn),相對(duì) synchronized 來(lái)說(shuō),它有一些重要的優(yōu)勢(shì),但是我認(rèn)為急于把 synchronized 視若敝屣,絕對(duì)是個(gè)嚴(yán)重的錯(cuò)誤。 java.util.concurrent.lock 中的鎖定類是用于高級(jí)用戶和高級(jí)情況的工具 。一般來(lái)說(shuō),除非您對(duì) Lock 的某個(gè)高級(jí)特性有明確的需要,或者有明確的證據(jù)(而不是僅僅是懷疑)表明在特定情況下,同步已經(jīng)成為可伸縮性的瓶頸,否則還是應(yīng)當(dāng)繼續(xù)使用 synchronized。

為什么我在一個(gè)顯然“更好的”實(shí)現(xiàn)的使用上主張保守呢?因?yàn)閷?duì)于 java.util.concurrent.lock 中的鎖定類來(lái)說(shuō),synchronized 仍然有一些優(yōu)勢(shì)。比如,在使用 synchronized 的時(shí)候,不能忘記釋放鎖;在退出 synchronized 塊時(shí),JVM 會(huì)為您做這件事。您很容易忘記用 finally 塊釋放鎖,這對(duì)程序非常有害。您的程序能夠通過(guò)測(cè)試,但會(huì)在實(shí)際工作中出現(xiàn)死鎖,那時(shí)會(huì)很難指出原因(這也是為什么根本不讓初級(jí)開(kāi)發(fā)人員使用 Lock 的一個(gè)好理由。)

另一個(gè)原因是因?yàn)椋?dāng) JVM 用 synchronized 管理鎖定請(qǐng)求和釋放時(shí),JVM 在生成線程轉(zhuǎn)儲(chǔ)時(shí)能夠包括鎖定信息。這些對(duì)調(diào)試非常有價(jià)值,因?yàn)樗鼈兡軜?biāo)識(shí)死鎖或者其他異常行為的來(lái)源。 Lock 類只是普通的類,JVM 不知道具體哪個(gè)線程擁有 Lock 對(duì)象。而且,幾乎每個(gè)開(kāi)發(fā)人員都熟悉 synchronized,它可以在 JVM 的所有版本中工作。在 JDK 5.0 成為標(biāo)準(zhǔn)(從現(xiàn)在開(kāi)始可能需要兩年)之前,使用 Lock 類將意味著要利用的特性不是每個(gè) JVM 都有的,而且不是每個(gè)開(kāi)發(fā)人員都熟悉的。

什么時(shí)候選擇用ReentrantLock 代替synchronized

既然如此,我們什么時(shí)候才應(yīng)該使用 ReentrantLock 呢?答案非常簡(jiǎn)單 —— 在確實(shí)需要一些 synchronized 所沒(méi)有的特性的時(shí)候,比如時(shí)間鎖等候、可中斷鎖等候、無(wú)塊結(jié)構(gòu)鎖、多個(gè)條件變量或者鎖投票。 ReentrantLock 還具有可伸縮性的好處,應(yīng)當(dāng)在高度爭(zhēng)用的情況下使用它,但是請(qǐng)記住,大多數(shù) synchronized 塊幾乎從來(lái)沒(méi)有出現(xiàn)過(guò)爭(zhēng)用,所以可以把高度爭(zhēng)用放在一邊。我建議用 synchronized 開(kāi)發(fā),直到確實(shí)證明 synchronized 不合適,而不要僅僅是假設(shè)如果使用 ReentrantLock “性能會(huì)更好”。請(qǐng)記住,這些是供高級(jí)用戶使用的高級(jí)工具。(而且,真正的高級(jí)用戶喜歡選擇能夠找到的最簡(jiǎn)單工具,直到他們認(rèn)為簡(jiǎn)單的工具不適用為止。)。一如既往,首先要把事情做好,然后再考慮是不是有必要做得更快。

結(jié)束語(yǔ)

Lock 框架是同步的兼容替代品,它提供了 synchronized 沒(méi)有提供的許多特性,它的實(shí)現(xiàn)在爭(zhēng)用下提供了更好的性能。但是,這些明顯存在的好處,還不足以成為用 ReentrantLock 代替 synchronized 的理由。相反,應(yīng)當(dāng)根據(jù)您是否 需要 ReentrantLock 的能力來(lái)作出選擇。大多數(shù)情況下,您不應(yīng)當(dāng)選擇它 —— synchronized 工作得很好,可以在所有 JVM 上工作,更多的開(kāi)發(fā)人員了解它,而且不太容易出錯(cuò)。只有在真正需要 Lock 的時(shí)候才用它。在這些情況下,您會(huì)很高興擁有這款工具。

【編輯推薦】

  1. Java 5.0 多線程編程實(shí)踐
  2. 使用Java建立穩(wěn)定的多線程服務(wù)器
  3. Java多線程程序設(shè)計(jì)初步
責(zé)任編輯:佚名 來(lái)源: 網(wǎng)絡(luò)轉(zhuǎn)載
相關(guān)推薦

2023-10-28 16:22:21

Go接口

2013-03-28 16:12:12

Message機(jī)制應(yīng)用

2009-07-08 17:33:46

JDK5.0內(nèi)置工具

2024-01-07 17:29:10

編程語(yǔ)言線程Rust

2009-07-07 17:34:15

collectionJDK5.0

2011-08-31 16:30:19

Lua多線程

2009-07-07 17:50:44

2021-03-11 16:34:57

css前端CSS 特效

2010-05-19 13:29:59

2024-05-06 00:00:01

鎖定機(jī)制編程

2009-06-25 10:33:53

StaticJava類

2012-01-10 10:05:47

文件目錄訪問(wèn)控制UGO

2011-03-11 09:20:35

jQueryjavascript

2009-07-09 11:02:37

JDK5.0內(nèi)置工具

2009-10-13 09:56:13

.NET多線程程序

2010-12-23 14:46:08

expect腳本

2022-11-04 09:01:33

SwiftPlottable

2011-06-08 16:56:37

VS2008 Qt

2011-10-26 10:12:53

Sencha Touc布局

2009-04-10 22:06:09

Vmwareesx虛擬化
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 亚洲国产成人精品女人久久久 | 成人h动漫亚洲一区二区 | 亚洲 中文 欧美 日韩 在线观看 | 国产大毛片 | 国产精品一区二区三区久久 | 亚洲a毛片 | 91视频进入 | www.天天操.com | 97碰碰碰 | 日韩一区二区三区在线 | av一级在线观看 | 亚洲精品免费看 | 久久久久网站 | 日韩在线精品视频 | 国产午夜精品一区二区三区在线观看 | 在线观看av网站永久 | 亚洲精品电影在线观看 | 亚洲精品成人网 | 97国产在线视频 | 日韩精品在线看 | 五月精品视频 | 国产精品一二三区 | 久久大陆 | 久草久| 91精品入口蜜桃 | 欧美综合网 | 亚洲精品国产精品国自产在线 | 毛片视频网站 | 久久极品 | 日韩在线一区二区三区 | 97色综合| 久久久久久中文字幕 | 国产欧美日韩久久久 | 污视频免费在线观看 | 成人影院午夜 | 亚洲高清在线 | 超碰97免费| 久久久精品网站 | 国产成人精品免高潮在线观看 | 久久国产激情视频 | 天天射色综合 |