精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

手寫線程池,對照學習ThreadPoolExecutor線程池實現原理!

開發 前端
當意識到這一點時,其實非常懷念小時候。放假的早上跑出去,喊上三五個伙伴,要不下河摸摸魚、彈彈玻璃球、打打pia、跳跳房子!一天下來真的不會感覺累,但現在如果是放假的一天,你的娛樂安排,很多時候會讓頭很累!

[[356801]]

本文轉載自微信公眾號「bugstack蟲洞棧」,作者小傅哥。轉載本文請聯系bugstack蟲洞棧公眾號。     

目錄

一、前言

二、面試題

三、線程池講解

  • 1. 先看個例子
  • 2. 手寫一個線程池
  • 3. 線程池源碼分析

四、總結

一、前言

人看手機,機器學習!

正好是2020年,看到這張圖還是蠻有意思的。以前小時候總會看到一些科技電影,講到機器人會怎樣怎樣,但沒想到人似乎被娛樂化的東西,搞成了低頭族、大肚子!

當意識到這一點時,其實非常懷念小時候。放假的早上跑出去,喊上三五個伙伴,要不下河摸摸魚、彈彈玻璃球、打打pia、跳跳房子!一天下來真的不會感覺累,但現在如果是放假的一天,你的娛樂安排,很多時候會讓頭很累!

「就像」,你有試過學習一天英語頭疼,還是刷一天抖音頭疼嗎?或者玩一天游戲與打一天球!如果你意識到了,那么爭取放下一會手機,適當娛樂,鍛煉保持個好身體!

二、面試題

謝飛機,小記!,上次吃虧在線程上,這次可能一次坑掉兩次了!

「謝飛機」:你問吧,我準備好了!!!

「面試官」:嗯,線程池狀態是如何設計存儲的?

「謝飛機」:這!下一個,下一個!

「面試官」:Worker 的實現類,為什么不使用 ReentrantLock 來實現呢,而是自己繼承AQS?

「謝飛機」:我...!

「面試官」:那你簡述下,execute 的執行過程吧!

「謝飛機」:再見!

三、線程池講解

1. 先看個例子

  1. ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(10)); 
  2. threadPoolExecutor.execute(() -> { 
  3.     System.out.println("Hi 線程池!"); 
  4. }); 
  5. threadPoolExecutor.shutdown(); 
  6.  
  7. // Executors.newFixedThreadPool(10); 
  8. // Executors.newCachedThreadPool(); 
  9. // Executors.newScheduledThreadPool(10); 
  10. // Executors.newSingleThreadExecutor(); 

這是一段用于創建線程池的例子,相信你已經用了很多次了。

線程池的核心目的就是資源的利用,避免重復創建線程帶來的資源消耗。因此引入一個池化技術的思想,避免重復創建、銷毀帶來的性能開銷。

「那么」,接下來我們就通過實踐的方式分析下這個池子的構造,看看它是如何處理線程的。

2. 手寫一個線程池

2.1 實現流程

為了更好的理解和分析關于線程池的源碼,我們先來按照線程池的思想,手寫一個非常簡單的線程池。

其實很多時候一段功能代碼的核心主邏輯可能并沒有多復雜,但為了讓核心流程順利運行,就需要額外添加很多分支的輔助流程。就像我常說的,為了保護手才把擦屁屁紙弄那么大!

圖 21-1 線程池簡化流程

關于圖 21-1,這個手寫線程池的實現也非常簡單,只會體現出核心流程,包括:

有n個一直在運行的線程,相當于我們創建線程池時允許的線程池大小。

把線程提交給線程池運行。

如果運行線程池已滿,則把線程放入隊列中。

最后當有空閑時,則獲取隊列中線程進行運行。

2.2 實現代碼

  1. public class ThreadPoolTrader implements Executor { 
  2.  
  3.     private final AtomicInteger ctl = new AtomicInteger(0); 
  4.  
  5.     private volatile int corePoolSize; 
  6.     private volatile int maximumPoolSize; 
  7.  
  8.     private final BlockingQueue<Runnable> workQueue; 
  9.  
  10.     public ThreadPoolTrader(int corePoolSize, int maximumPoolSize, BlockingQueue<Runnable> workQueue) { 
  11.         this.corePoolSize = corePoolSize; 
  12.         this.maximumPoolSize = maximumPoolSize; 
  13.         this.workQueue = workQueue; 
  14.     } 
  15.  
  16.     @Override 
  17.     public void execute(Runnable command) { 
  18.         int c = ctl.get(); 
  19.         if (c < corePoolSize) { 
  20.             if (!addWorker(command)) { 
  21.                 reject(); 
  22.             } 
  23.             return
  24.         } 
  25.         if (!workQueue.offer(command)) { 
  26.             if (!addWorker(command)) { 
  27.                 reject(); 
  28.             } 
  29.         } 
  30.     } 
  31.  
  32.     private boolean addWorker(Runnable firstTask) { 
  33.         if (ctl.get() >= maximumPoolSize) return false
  34.  
  35.         Worker worker = new Worker(firstTask); 
  36.         worker.thread.start(); 
  37.         ctl.incrementAndGet(); 
  38.         return true
  39.     } 
  40.  
  41.     private final class Worker implements Runnable { 
  42.  
  43.         final Thread thread; 
  44.         Runnable firstTask; 
  45.  
  46.         public Worker(Runnable firstTask) { 
  47.             this.thread = new Thread(this); 
  48.             this.firstTask = firstTask; 
  49.         } 
  50.  
  51.         @Override 
  52.         public void run() { 
  53.             Runnable task = firstTask; 
  54.             try { 
  55.                 while (task != null || (task = getTask()) != null) { 
  56.                     task.run(); 
  57.                     if (ctl.get() > maximumPoolSize) { 
  58.                         break; 
  59.                     } 
  60.                     task = null
  61.                 } 
  62.             } finally { 
  63.                 ctl.decrementAndGet(); 
  64.             } 
  65.         } 
  66.  
  67.         private Runnable getTask() { 
  68.             for (; ; ) { 
  69.                 try { 
  70.                     System.out.println("workQueue.size:" + workQueue.size()); 
  71.                     return workQueue.take(); 
  72.                 } catch (InterruptedException e) { 
  73.                     e.printStackTrace(); 
  74.                 } 
  75.             } 
  76.         } 
  77.     } 
  78.  
  79.     private void reject() { 
  80.         throw new RuntimeException("Error!ctl.count:" + ctl.get() + " workQueue.size:" + workQueue.size()); 
  81.     } 
  82.  
  83.     public static void main(String[] args) { 
  84.         ThreadPoolTrader threadPoolTrader = new ThreadPoolTrader(2, 2, new ArrayBlockingQueue<Runnable>(10)); 
  85.  
  86.         for (int i = 0; i < 10; i++) { 
  87.             int finalI = i; 
  88.             threadPoolTrader.execute(() -> { 
  89.                 try { 
  90.                     Thread.sleep(1500); 
  91.                 } catch (InterruptedException e) { 
  92.                     e.printStackTrace(); 
  93.                 } 
  94.                 System.out.println("任務編號:" + finalI); 
  95.             }); 
  96.         } 
  97.     } 
  98.  
  99.  
  100. // 測試結果 
  101.  
  102. 任務編號:1 
  103. 任務編號:0 
  104. workQueue.size:8 
  105. workQueue.size:8 
  106. 任務編號:3 
  107. workQueue.size:6 
  108. 任務編號:2 
  109. workQueue.size:5 
  110. 任務編號:5 
  111. workQueue.size:4 
  112. 任務編號:4 
  113. workQueue.size:3 
  114. 任務編號:7 
  115. workQueue.size:2 
  116. 任務編號:6 
  117. workQueue.size:1 
  118. 任務編號:8 
  119. 任務編號:9 
  120. workQueue.size:0 
  121. workQueue.size:0 

「以上」,關于線程池的實現還是非常簡單的,從測試結果上已經可以把最核心的池化思想體現出來了。主要功能邏輯包括:

  • ctl,用于記錄線程池中線程數量。
  • corePoolSize、maximumPoolSize,用于限制線程池容量。
  • workQueue,線程池隊列,也就是那些還不能被及時運行的線程,會被裝入到這個隊列中。
  • execute,用于提交線程,這個是通用的接口方法。在這個方法里主要實現的就是,當前提交的線程是加入到worker、隊列還是放棄。
  • addWorker,主要是類 Worker 的具體操作,創建并執行線程。這里還包括了 getTask() 方法,也就是從隊列中不斷的獲取未被執行的線程。

「好」,那么以上呢,就是這個簡單線程池實現的具體體現。但如果深思熟慮就會發現這里需要很多完善,比如:線程池狀態呢,不可能一直奔跑呀!?、線程池的鎖呢,不會有并發問題嗎?、線程池拒絕后的策略呢?,這些問題都沒有在主流程解決,也正因為沒有這些流程,所以上面的代碼才更容易理解。

接下來,我們就開始分析線程池的源碼,與我們實現的簡單線程池參考對比,會更加容易理解??!

3. 線程池源碼分析

3.1 線程池類關系圖

圖 21-2 線程池類關系圖

以圍繞核心類 ThreadPoolExecutor 的實現展開的類之間實現和繼承關系,如圖 21-2 線程池類關系圖。

  • 接口 Executor、ExecutorService,定義線程池的基本方法。尤其是 execute(Runnable command) 提交線程池方法。
  • 抽象類 AbstractExecutorService,實現了基本通用的接口方法。
  • ThreadPoolExecutor,是整個線程池最核心的工具類方法,所有的其他類和接口,為圍繞這個類來提供各自的功能。
  • Worker,是任務類,也就是最終執行的線程的方法。
  • RejectedExecutionHandler,是拒絕策略接口,有四個實現類;AbortPolicy(拋異常方式拒絕)、DiscardPolicy(直接丟棄)、DiscardOldestPolicy(丟棄存活時間最長的任務)、CallerRunsPolicy(誰提交誰執行)。
  • Executors,是用于創建我們常用的不同策略的線程池,newFixedThreadPool、newCachedThreadPool、newScheduledThreadPool、newSingleThreadExecutor。

3.2 高3位與低29位

圖 22-3 線程狀態,高3位與低29位

  1. private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); 
  2. private static final int COUNT_BITS = Integer.SIZE - 3; 
  3. private static final int CAPACITY   = (1 << COUNT_BITS) - 1; 
  4.  
  5. private static final int RUNNING    = -1 << COUNT_BITS; 
  6. private static final int SHUTDOWN   =  0 << COUNT_BITS; 
  7. private static final int STOP       =  1 << COUNT_BITS; 
  8. private static final int TIDYING    =  2 << COUNT_BITS; 
  9. private static final int TERMINATED =  3 << COUNT_BITS; 

在 ThreadPoolExecutor 線程池實現類中,使用 AtomicInteger 類型的 ctl 記錄線程池狀態和線程池數量。在一個類型上記錄多個值,它采用的分割數據區域,高3位記錄狀態,低29位存儲線程數量,默認 RUNNING 狀態,線程數為0個。

3.2 線程池狀態

圖 22-4 線程池狀態流轉

圖 22-4 是線程池中的狀態流轉關系,包括如下狀態:

  • RUNNING:運行狀態,接受新的任務并且處理隊列中的任務。
  • SHUTDOWN:關閉狀態(調用了shutdown方法)。不接受新任務,,但是要處理隊列中的任務。
  • STOP:停止狀態(調用了shutdownNow方法)。不接受新任務,也不處理隊列中的任務,并且要中斷正在處理的任務。
  • TIDYING:所有的任務都已終止了,workerCount為0,線程池進入該狀態后會調 terminated() 方法進入TERMINATED 狀態。
  • TERMINATED:終止狀態,terminated() 方法調用結束后的狀態。

3.3 提交線程(execute)

圖 22-5 提交線程流程圖

  1. public void execute(Runnable command) { 
  2.     if (command == null
  3.         throw new NullPointerException(); 
  4.     int c = ctl.get(); 
  5.     if (workerCountOf(c) < corePoolSize) { 
  6.         if (addWorker(command, true)) 
  7.             return
  8.         c = ctl.get(); 
  9.     } 
  10.     if (isRunning(c) && workQueue.offer(command)) { 
  11.         int recheck = ctl.get(); 
  12.         if (! isRunning(recheck) && remove(command)) 
  13.             reject(command); 
  14.         else if (workerCountOf(recheck) == 0) 
  15.             addWorker(nullfalse); 
  16.     } 
  17.     else if (!addWorker(command, false)) 
  18.         reject(command); 

在閱讀這部分源碼的時候,可以參考我們自己實現的線程池。其實最終的目的都是一樣的,就是這段被提交的線程,啟動執行、加入隊列、決策策略,這三種方式。

  • ctl.get(),取的是記錄線程狀態和線程個數的值,最終需要使用方法 workerCountOf(),來獲取當前線程數量。`workerCountOf 執行的是 c & CAPACITY 運算
  • 根據當前線程池中線程數量,與核心線程數 corePoolSize 做對比,小于則進行添加線程到任務執行隊列。
  • 如果說此時線程數已滿,那么則需要判斷線程池是否為運行狀態 isRunning(c)。如果是運行狀態則把不能被執行的線程放入線程隊列中。
  • 放入線程隊列以后,還需要重新判斷線程是否運行以及移除操作,如果非運行且移除,則進行拒絕策略。否則判斷線程數量為0后添加新線程。
  • 最后就是再次嘗試添加任務執行,此時方法 addWorker 的第二個入參是 false,最終會影響添加執行任務數量判斷。如果添加失敗則進行拒絕策略。

3.5 添加執行任務(addWorker)

圖 22-6 添加執行任務邏輯流程

「private boolean addWorker(Runnable firstTask, boolean core)」

「第一部分、增加線程數量」

  1. retry: 
  2. for (;;) { 
  3.     int c = ctl.get(); 
  4.     int rs = runStateOf(c); 
  5.     // Check if queue empty only if necessary. 
  6.     if (rs >= SHUTDOWN && 
  7.         ! (rs == SHUTDOWN && 
  8.            firstTask == null && 
  9.            ! workQueue.isEmpty())) 
  10.         return false
  11.     for (;;) { 
  12.         int wc = workerCountOf(c); 
  13.         if (wc >= CAPACITY || 
  14.             wc >= (core ? corePoolSize : maximumPoolSize)) 
  15.             return false
  16.         if (compareAndIncrementWorkerCount(c)) 
  17.             break retry; 
  18.         c = ctl.get();  // Re-read ctl 
  19.         if (runStateOf(c) != rs) 
  20.             continue retry; 
  21.         // else CAS failed due to workerCount change; retry inner loop 
  22.     } 

「第一部分、創建啟動線程」

  1. boolean workerStarted = false
  2. boolean workerAdded = false
  3. Worker w = null
  4. try { 
  5.     w = new Worker(firstTask); 
  6.     final Thread t = w.thread; 
  7.     if (t != null) { 
  8.         final ReentrantLock mainLock = this.mainLock; 
  9.         mainLock.lock(); 
  10.         try { 
  11.             int rs = runStateOf(ctl.get()); 
  12.             if (rs < SHUTDOWN || 
  13.                 (rs == SHUTDOWN && firstTask == null)) { 
  14.                 if (t.isAlive()) // precheck that t is startable 
  15.                     throw new IllegalThreadStateException(); 
  16.                 workers.add(w); 
  17.                 int s = workers.size(); 
  18.                 if (s > largestPoolSize) 
  19.                     largestPoolSize = s; 
  20.                 workerAdded = true
  21.             } 
  22.         } finally { 
  23.             mainLock.unlock(); 
  24.         } 
  25.         if (workerAdded) { 
  26.             t.start(); 
  27.             workerStarted = true
  28.         } 
  29.     } 
  30. } finally { 
  31.     if (! workerStarted) 
  32.         addWorkerFailed(w); 
  33. return workerStarted; 

添加執行任務的流程可以分為兩塊看,上面代碼部分是用于記錄線程數量、下面代碼部分是在獨占鎖里創建執行線程并啟動。這部分代碼在不看鎖、CAS等操作,那么就和我們最開始手寫的線程池基本一樣了

  • if (rs >= SHUTDOWN &&! (rs == SHUTDOWN &&firstTask == null &&! workQueue.isEmpty())),判斷當前線程池狀態,是否為 SHUTDOWN、STOP、TIDYING、TERMINATED中的一個。并且當前狀態為 SHUTDOWN、且傳入的任務為 null,同時隊列不為空。那么就返回 false。
  • compareAndIncrementWorkerCount,CAS 操作,增加線程數量,成功就會跳出標記的循環體。
  • runStateOf(c) != rs,最后是線程池狀態判斷,決定是否循環。
  • 在線程池數量記錄成功后,則需要進入加鎖環節,創建執行線程,并記錄狀態。在最后如果判斷沒有啟動成功,則需要執行 addWorkerFailed 方法,剔除到線程方法等操作。

3.6 執行線程(runWorker)

  1. final void runWorker(Worker w) { 
  2.     Thread wt = Thread.currentThread(); 
  3.     Runnable task = w.firstTask; 
  4.     w.firstTask = null
  5.     w.unlock(); // 允許中斷 
  6.     boolean completedAbruptly = true
  7.     try { 
  8.         while (task != null || (task = getTask()) != null)  
  9.             w.lock(); 
  10.             if ((runStateAtLeast(ctl.get(), STOP) || 
  11.                  (Thread.interrupted() && 
  12.                   runStateAtLeast(ctl.get(), STOP))) && 
  13.                 !wt.isInterrupted()) 
  14.                 wt.interrupt(); 
  15.             try { 
  16.                 beforeExecute(wt, task); 
  17.                 Throwable thrown = null
  18.                 try { 
  19.                     task.run(); 
  20.                 } finally { 
  21.                     afterExecute(task, thrown); 
  22.                 } 
  23.             } finally { 
  24.                 task = null
  25.                 w.completedTasks++; 
  26.                 w.unlock(); 
  27.             } 
  28.         } 
  29.         completedAbruptly = false
  30.     } finally { 
  31.         processWorkerExit(w, completedAbruptly); 
  32.     } 

「其實」,有了手寫線程池的基礎,到這也就基本了解了,線程池在干嘛。到這最核心的點就是 task.run() 讓線程跑起來。額外再附帶一些其他流程如下;

  • beforeExecute、afterExecute,線程執行的前后做一些統計信息。
  • 另外這里的鎖操作是 Worker 繼承 AQS 自己實現的不可重入的獨占鎖。
  • processWorkerExit,如果你感興趣,類似這樣的方法也可以深入了解下。在線程退出時候workers做到一些移除處理以及完成任務數等,也非常有意思

3.7 隊列獲取任務(getTask)

如果你已經開始閱讀源碼,可以在 runWorker 方法中,看到這樣一句循環代碼 while (task != null || (task = getTask()) != null)。這與我們手寫線程池中操作的方式是一樣的,核心目的就是從隊列中獲取線程方法。

  1. private Runnable getTask() { 
  2.     boolean timedOut = false; // Did the last poll() time out
  3.     for (;;) { 
  4.         int c = ctl.get(); 
  5.         int rs = runStateOf(c); 
  6.         // Check if queue empty only if necessary. 
  7.         if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { 
  8.             decrementWorkerCount(); 
  9.             return null
  10.         } 
  11.         int wc = workerCountOf(c); 
  12.         // Are workers subject to culling? 
  13.         boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; 
  14.         if ((wc > maximumPoolSize || (timed && timedOut)) 
  15.             && (wc > 1 || workQueue.isEmpty())) { 
  16.             if (compareAndDecrementWorkerCount(c)) 
  17.                 return null
  18.             continue
  19.         } 
  20.         try { 
  21.             Runnable r = timed ? 
  22.                 workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : 
  23.                 workQueue.take(); 
  24.             if (r != null
  25.                 return r; 
  26.             timedOut = true
  27.         } catch (InterruptedException retry) { 
  28.             timedOut = false
  29.         } 
  30.     } 
  • getTask 方法從阻塞隊列中獲取等待被執行的任務,也就是一條條往出拿線程方法。
  • if (rs >= SHUTDOWN ...,判斷線程是否關閉。
  • wc = workerCountOf(c),wc > corePoolSize,如果工作線程數超過核心線程數量 corePoolSize 并且 workQueue 不為空,則增加工作線程。但如果超時未獲取到線程,則會把大于 corePoolSize 的線程銷毀掉。
  • timed,是 allowCoreThreadTimeOut 得來的。最終 timed 為 true 時,則通過阻塞隊列的poll方法進行超時控制。
  • 如果在 keepAliveTime 時間內沒有獲取到任務,則返回null。如果為false,則阻塞。

四、總結

這一章節并沒有完全把線程池的所有知識點都介紹完,否則一篇內容會有些臃腫。在這一章節我們從手寫線程池開始,逐步的分析這些代碼在Java的線程池中是如何實現的,涉及到的知識點也幾乎是我們以前介紹過的內容,包括:隊列、CAS、AQS、重入鎖、獨占鎖等內容。所以這些知識也基本是環環相扣的,最好有一些根基否則會有些不好理解。

除了本章介紹的,我們還沒有講到線程的銷毀過程、四種線程池方法的選擇和使用、以及在CPU密集型任務、IO 密集型任務時該怎么配置。另外在Spring中也有自己實現的線程池方法。這些知識點都非常貼近實際操作。

好了,今天的內容先扯到這,后續的內容陸續完善。如果以上內容有錯字、流程缺失、或者不好理解以及描述錯誤,歡迎留言。互相學習、互相進步。

 

責任編輯:武曉燕 來源: bugstack蟲洞棧
相關推薦

2021-09-11 07:32:15

Java線程線程池

2020-12-08 08:53:53

編程ThreadPoolE線程池

2025-09-24 18:39:45

2015-10-10 09:39:42

Java線程池源碼解析

2020-03-05 15:34:16

線程池C語言局域網

2012-05-15 02:18:31

Java線程池

2021-12-28 15:10:01

線程池C語言編程語言

2022-03-09 09:43:01

工具類線程項目

2024-07-15 08:20:24

2020-07-08 12:05:55

Java線程池策略

2018-10-31 15:54:47

Java線程池源碼

2023-05-19 08:01:24

Key消費場景

2022-03-22 09:20:57

應用線程池技術

2022-11-09 09:01:08

并發編程線程池

2012-02-01 11:20:23

Java線程

2023-11-29 16:38:12

線程池阻塞隊列開發

2020-12-10 07:00:38

編程線程池定時任務

2021-05-26 11:30:24

Java線程池代碼

2023-10-13 08:20:02

Spring線程池id

2022-09-26 00:48:14

線程池阻塞數據
點贊
收藏

51CTO技術棧公眾號

在线成人一区二区| 一区二区三区四区av| 91精品国产电影| 成人性生活免费看| 在线观看网站免费入口在线观看国内 | 欧美一区二区视频在线观看2022 | 亚洲已满18点击进入久久| 成人三级视频在线观看一区二区| 久久久久久久蜜桃| 亚洲精选av| 色综合天天天天做夜夜夜夜做| 婷婷精品国产一区二区三区日韩| 91久久国语露脸精品国产高跟| 国产在线成人| 国产午夜精品视频| 秋霞午夜鲁丝一区二区| 亚洲人体视频| 国产日韩av一区| 亚洲一区二区久久久久久| 国产精品美女毛片真酒店| 亚洲欧美校园春色| 91精品国产综合久久精品 | 岛国成人毛片| 国产精品伊人色| 欧美亚洲日本网站| 中文字幕观看av| 欧美成人一区在线观看| 欧美日韩国产中文| 97国产精东麻豆人妻电影| 嫩草在线视频| 99久久久无码国产精品| 国产欧美一区二区三区久久人妖| 国产一区二区播放| 先锋影音国产精品| 日韩你懂的在线播放| 日本va中文字幕| 美女航空一级毛片在线播放| 26uuu亚洲综合色| 亚洲xxxx视频| 亚洲熟妇av乱码在线观看| 日韩午夜免费| 欧美成人精品激情在线观看| a天堂中文字幕| 丁香一区二区| 日韩一区二区影院| 天天色综合天天色| 一区二区三区短视频| 国产精品久久看| 免费在线成人av电影| 丰满少妇一级片| 国产福利一区在线| 成人美女免费网站视频| 国产精品露脸视频| 久久综合伊人| 69av视频在线播放| 九九热这里有精品视频| 久久国产影院| 色小说视频一区| b站大片免费直播| 欧美性生活一级片| 亚洲国产另类久久精品 | 国产精品av久久久久久无| 精品国内亚洲2022精品成人| 日韩精品一区二区三区在线播放| www.成人黄色| 成人欧美magnet| 欧美日韩美女在线观看| 国产免费一区二区视频| 1769免费视频在线观看| 亚洲欧美激情小说另类| 青青草影院在线观看| 黄色大片在线播放| 亚洲视频免费在线| 在线观看18视频网站| 免费在线观看av网站| 国产精品久久久久久久岛一牛影视 | 国产曰批免费观看久久久| 国产精品视频免费观看www| 最近免费中文字幕大全免费版视频| 日韩一区二区免费看| 久久久久久一区二区三区| 久久久久久久国产精品毛片| 亚洲精品一区二区妖精| 另类美女黄大片| 九九热精品在线观看| 国产一区观看| 91精品成人久久| 99精品在线播放| 亚洲欧美日韩精品一区二区| 人人爽久久涩噜噜噜网站| 久久精品五月天| 六月丁香婷婷久久| 91在线精品播放| 亚洲第一免费视频| 91免费国产视频网站| 欧美一区二区福利| 在线看黄色av| 夜夜精品视频一区二区 | 99在线视频首页| 日本中文字幕电影在线观看 | 国产精品99久久久久久久| 天天色棕合合合合合合合| 久久久久久**毛片大全| 亚洲欧美日韩不卡一区二区三区| 男人在线资源站| 亚洲成av人片www| 欧美少妇性生活视频| 香蕉久久一区| 精品国产乱码久久久久久闺蜜| aa片在线观看视频在线播放| 欧美一级本道电影免费专区| 萌白酱国产一区二区| 五月婷婷色丁香| 国模娜娜一区二区三区| 国产在线欧美日韩| 在线观看的av| 亚洲va国产天堂va久久en| 成人3d动漫一区二区三区| japansex久久高清精品| 亚洲精品视频播放| 免费看的黄色网| 一区在线免费观看| 国产精品第二页| 亚洲AV无码精品色毛片浪潮| 国产日本一区二区| www.在线观看av| 六九午夜精品视频| 日韩hd视频在线观看| 91n在线视频| 米奇777在线欧美播放| www.久久草| 午夜视频在线| 色综合亚洲欧洲| 麻豆av免费看| 亚洲mv大片欧洲mv大片| 日本亚洲欧美三级| 国产不卡av在线播放| 欧美激情中文不卡| 男人添女荫道口图片| 九七电影院97理论片久久tvb| 亚洲精品电影网站| 加勒比婷婷色综合久久| 免费不卡在线观看| 免费久久99精品国产自| 免费在线观看av电影| 欧美精品在欧美一区二区少妇| 欧美bbbbb性bbbbb视频| 亚洲精品影视| 国产欧美韩日| 免费大片在线观看www| 欧美午夜影院一区| 9.1成人看片免费版| 亚洲精品婷婷| 精品久久久久久亚洲| 三级网站视频在在线播放| 5858s免费视频成人| 一本在线免费视频| 日本va欧美va欧美va精品| 欧美xxxx黑人又粗又长精品| 欧美人体视频xxxxx| 日韩精品在线网站| 黄色一级视频免费| 国产成人日日夜夜| 亚洲人一区二区| 高清亚洲高清| 视频直播国产精品| 亚洲自拍偷拍另类| 中文字幕av资源一区| 黄色高清无遮挡| 妖精视频一区二区三区免费观看| 国产91ⅴ在线精品免费观看| 午夜影院在线视频| 亚洲一区二区三区在线播放| 亚洲av无码一区东京热久久| 在线精品一区二区| 久久福利电影| 亚洲成人短视频| 亚洲欧洲午夜一线一品| 天天爱天天做天天爽| 欧美国产激情一区二区三区蜜月| 手机在线看福利| 日韩欧美精品一区| 成人午夜一级二级三级| www免费网站在线观看| 色先锋久久av资源部| www..com.cn蕾丝视频在线观看免费版| 免费成人性网站| 米仓穗香在线观看| 国产精品一线| 国产精品91久久| 久久综合之合合综合久久| 日韩一二三四区| 欧美另类一区二区| 国产精品久久三| 97中文字幕在线观看| 亚洲一区视频| 亚洲精品中字| 99香蕉久久| 国产精品久久久久久av福利| 精品51国产黑色丝袜高跟鞋| 精品国产麻豆免费人成网站| 国产又大又粗又爽| 国产精品免费av| 精品少妇人妻av一区二区三区| 久久精品天堂| 成人毛片100部免费看| 小嫩嫩12欧美| 亚洲一区二区三区乱码aⅴ蜜桃女 亚洲一区二区三区乱码aⅴ | 欧美7777| 欧美成人精品激情在线观看| 蜜桃视频在线观看网站| 欧美一区二区三区在线看| 亚洲av鲁丝一区二区三区| 91污片在线观看| 亚洲理论中文字幕| 亚洲欧洲日本一区二区三区| 日韩av电影免费在线观看| 视频欧美一区| 国产日本欧美一区| 大黄网站在线观看| 在线精品91av| 天堂av在线资源| 欧美一区二区三区的| 中文字幕日韩一级| 亚洲免费色视频| japanese中文字幕| 国产99久久久国产精品| 日批视频在线免费看| 在线成人直播| 亚洲一区三区视频在线观看| 一区二区美女| 国产一区二区在线网站| 国产成人免费av一区二区午夜| 韩国福利视频一区| av网站在线免费看推荐| 亚洲欧洲黄色网| 亚洲av成人精品日韩在线播放| 这里是久久伊人| 一区精品在线观看| 色婷婷av一区二区| 国产成人精品一区二三区| 一区二区三区av电影 | 国产精品久久久久久久久图文区| 国产又爽又黄无码无遮挡在线观看| 国产精品一区二区三区乱码| 亚欧在线免费观看| 视频一区欧美日韩| 久久成人免费观看| 欧美在线黄色| 中文字幕日韩一区二区三区不卡| 国产免费久久| 久久精品五月婷婷| 蜜桃视频在线观看网站| 亚洲电影第1页| 丝袜+亚洲+另类+欧美+变态| 亚洲人高潮女人毛茸茸| 高清在线观看av| 久久精品视频一| 国精一区二区三区| 欧美性在线观看| 精品日韩视频| 国产日韩av在线| 日韩精品一区二区三区中文| 国产不卡一区二区在线观看| 看全色黄大色大片免费久久久| 美脚丝袜一区二区三区在线观看| 久久99蜜桃| 欧美日韩视频免费在线观看| 欧美精品aa| 日韩中文字幕在线视频观看| 久久一日本道色综合久久| 色噜噜狠狠一区二区| 国产福利一区二区三区视频在线 | 久久夜色电影| 日本婷婷久久久久久久久一区二区| 成人在线免费观看视频| 日韩在线视频在线| 亚洲一区二区免费看| 在线观看亚洲色图| 国产精品中文字幕日韩精品| 香蕉视频黄色在线观看| 国产精品久久99| 四虎永久在线精品| 欧美日韩午夜在线视频| 韩国av永久免费| 国产亚洲人成网站在线观看| av网站网址在线观看| 国产成人综合精品| 国产麻豆精品| 欧美日韩中文国产一区发布| 亚洲色图88| 欧美日韩亚洲一二三| 国产精品一区二区果冻传媒| 日韩精品卡通动漫网站| 亚洲男人的天堂在线观看| 欧美一区二区三区网站| 日韩午夜三级在线| 精品久久av| 久久噜噜噜精品国产亚洲综合| 2019年精品视频自拍| 国产精品久久久对白| 久久人人88| 久久精品.com| 成人avav在线| 色婷婷粉嫩av| 欧美天天综合色影久久精品| 国产成人精品一区二三区四区五区| 亚洲欧美日本精品| 黄网av在线| 91久久极品少妇xxxxⅹ软件| 日韩88av| 国产精品69页| av成人动漫在线观看| 青青草手机视频在线观看| 欧美日韩亚洲国产综合| 国产一区二区三区福利| 97碰在线观看| 99re热精品视频| 五月天激情图片| 久草在线在线精品观看| 国产精品毛片一区二区| 精品免费在线视频| 免费的黄色av| 欧美精品激情在线观看| 欧美成人精品一级| 中文字幕一区二区三区四区五区六区| 免费在线成人| 伦理片一区二区| 亚洲午夜精品一区二区三区他趣| 国产精品热久久| 日韩视频一区在线| 韩国精品视频在线观看| 色噜噜狠狠色综合网| 三级影片在线观看欧美日韩一区二区 | 福利一区二区免费视频| 青娱乐国产91| 日韩av一二三| 国产调教在线观看| 欧美性一级生活| youjizz在线播放| 国产精品爽黄69天堂a| 成人免费在线播放| 亚洲不卡视频在线| 国产精品入口麻豆九色| 中文字幕在线2019| 中文字幕亚洲综合| 视频欧美精品| 成人在线免费观看网址| 国产很黄免费观看久久| 九九热只有精品| 亚洲国产精久久久久久久| 黄在线观看免费网站ktv| 久中文字幕一区| 日本亚洲三级在线| av在线免费播放网址| 日韩一区二区在线观看| 七七成人影院| 精品不卡在线| 日韩国产成人精品| 老司机深夜福利网站| 日韩视频免费直播| 嗯啊主人调教在线播放视频 | 国产 中文 字幕 日韩 在线| 五月天中文字幕一区二区| 欧美美女色图| 国产精品直播网红| 午夜精品免费| 特大黑人巨人吊xxxx| 欧美吞精做爰啪啪高潮| 国产cdts系列另类在线观看| 国产精品国产精品国产专区不卡| 亚洲欧洲视频| 国产精品久久久久久成人| 欧美一级理论性理论a| 国产直播在线| 亚洲精品中字| 成人福利视频在线| 中文字幕免费视频观看| 插插插亚洲综合网| 色老板在线视频一区二区| www.日本一区| 一区二区三区四区不卡视频 | 久久99久久99精品免观看粉嫩| 国产乱人伦丫前精品视频| 91看片就是不一样| 亚洲免费电影在线| 精品99又大又爽又硬少妇毛片| 国产综合久久久久久| 亚洲三级网站| 久久福利免费视频| 精品一区二区三区电影| av在线播放一区二区| 国产精品欧美激情在线观看| 亚洲欧洲韩国日本视频| 天天躁日日躁狠狠躁伊人| 国产在线精品一区免费香蕉 | 天堂在线观看视频| 国产精品一区二区3区| 亚洲久久视频| 91杏吧porn蝌蚪|