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

一個ThreadLocal和面試官大戰30個回合

開發 前端
首先我們通過ThreadLocal userInfoThreadLocal = new ThreadLocal() 初始化了一個Threadlocal 對象,就是上圖中說的Threadlocal 引用,這個引用指向堆中的ThreadLocal 對象;然后我們調用userInfoThreadLocal.set(userInfo); 這里做了什么事呢?

 [[397941]]

本文轉載自微信公眾號「安琪拉的博客」,作者安琪拉的博客。轉載本文請聯系安琪拉的博客公眾號。

開場

杭州某商務樓里,正發生著一起求職者和面試官的battle。

面試官:你先自我介紹一下。

安琪拉:面試官你好,我是草叢三婊,最強中單(妲己不服),草地摩托車車手,第21套廣播體操推廣者,火的傳人安琪拉,這是我的簡歷,請過目。

面試官:看你簡歷上寫熟悉多線程編程,熟悉到什么程度?

安琪拉:精通。

對。。。,你沒看錯,問就是“精通”,把666打在評論區。

面試官:

[心想] 莫不是個憨批,上來就說自己精通,誰把精通掛嘴上,莫不是個愣頭青嘞!

面試官:那我們開始吧。用過Threadlocal 吧?

安琪拉:用過。

面試官:那你跟我講講 ThreadLocal 在你們項目中的用法吧。

安琪拉:我們項目屬于保密項目,無可奉告,你還是換個問題吧!

面試官:那說個不保密的項目,或者你直接告訴我Threadlocal 的實現原理吧。 

正題

安琪拉:show time。。。

安琪拉:舉個栗子,我們支付寶每秒鐘同時會有很多用戶請求,那每個請求都帶有用戶信息,我們知道通常都是一個線程處理一個用戶請求,我們可以把用戶信息丟到Threadlocal里面,讓每個線程處理自己的用戶信息,線程之間互不干擾。

面試官:等等,問你個私人問題,為什么從支付寶跑出來面試,受不了PUA了嗎?

安琪拉:PUA我,不存在的,能PUA我的人還沒出生呢!公司食堂吃膩了,想換換口味。

面試官:那你來給我講講Threadlocal是干什么的?

安琪拉:Threadlocal 主要用來做線程變量的隔離,這么說可能不是很直觀。

還是說前面提到的例子,我們程序在處理用戶請求的時候,通常后端服務器是有一個線程池,來一個請求就交給一個線程來處理,那為了防止多線程并發處理請求的時候發生串數據,比如AB線程分別處理安琪拉和妲己的請求,A線程本來處理安琪拉的請求,結果訪問到妲己的數據上了,把妲己支付寶的錢轉走了。

所以就可以把安琪拉的數據跟A線程綁定,線程處理完之后解除綁定。

面試官:那把你剛才說的場景用偽代碼實現一下,來筆給你!

安琪拉:ok

  1. //存放用戶信息的ThreadLocal 
  2. private static final ThreadLocal<UserInfo> userInfoThreadLocal = new ThreadLocal<>(); 
  3.  
  4. public Response handleRequest(UserInfo userInfo) { 
  5.   Response response = new Response(); 
  6.   try { 
  7.     // 1.用戶信息set到線程局部變量中 
  8.     userInfoThreadLocal.set(userInfo); 
  9.     doHandle(); 
  10.   } finally { 
  11.     // 3.使用完移除掉 
  12.     userInfoThreadLocal.remove(); 
  13.   } 
  14.  
  15.   return response; 
  16.      
  17. //業務邏輯處理 
  18. private void doHandle () { 
  19.   // 2.實際用的時候取出來 
  20.   UserInfo userInfo = userInfoThreadLocal.get(); 
  21.   //查詢用戶資產 
  22.   queryUserAsset(userInfo); 

1.2.3 步驟很清楚了。

面試官:那你跟我說說Threadlocal 怎么實現線程變量的隔離的?

安琪拉:Oh, 這么快進入正題,我先給你畫個圖,如下:

面試官:圖我看了,那你對著前面你寫的代碼講一下對應圖中流程。

安琪拉:沒問題

  • 首先我們通過ThreadLocal userInfoThreadLocal = new ThreadLocal() 初始化了一個Threadlocal 對象,就是上圖中說的Threadlocal 引用,這個引用指向堆中的ThreadLocal 對象;
  • 然后我們調用userInfoThreadLocal.set(userInfo); 這里做了什么事呢?

我們把源代碼拿出來,看一看就清晰了。

我們知道 Thread 類有個 ThreadLocalMap 成員變量,這個Map key是Threadlocal 對象,value是你要存放的線程局部變量。

  1. # Threadlocal類 Threadlocal.class  
  2. public void set(T value) { 
  3.   //獲取當前線程Thread,就是上圖畫的Thread 引用 
  4.   Thread t = Thread.currentThread();  
  5.   //Thread類有個成員變量ThreadlocalMap,拿到這個Map 
  6.   ThreadLocalMap map = getMap(t); 
  7.   if (map != null
  8.     //this指的就是Threadlocal對象 
  9.     map.set(this, value); 
  10.   else 
  11.     createMap(t, value); 
  12.  
  13. ThreadLocalMap getMap(Thread t) { 
  14.   //獲取線程的ThreadLocalMap 
  15.   return t.threadLocals; 
  16.  
  17. void createMap(Thread t, T firstValue) { 
  18.   //初始化 
  19.   t.threadLocals = new ThreadLocalMap(this, firstValue); 
  1. # Thread類 Thread.class 
  2. public class Thread implements Runnable { 
  3.     //每個線程都有自己的ThreadLocalMap 成員變量 
  4.     ThreadLocal.ThreadLocalMap threadLocals = null

這里是在當前線程對象的ThreadlocalMap中put了一個元素(Entry),key是Threadlocal對象,value是userInfo。

理解兩件事就都清楚了:

ThreadLocalMap 類的定義在 Threadlocal中。

  • 第一,Thread 對象是Java語言中線程運行的載體,每個線程都有對應的Thread 對象,存放線程相關的一些信息,
  • 第二,Thread類中有個成員變量ThreadlocalMap,你就把他當成普通的Map,key存放的是Threadlocal對象,value是你要跟線程綁定的值(線程隔離的變量),比如這里是用戶信息對象(UserInfo)。

面試官:你剛才說Thread 類有個 ThreadlocalMap 屬性的成員變量,但是ThreadlocalMap 的定義卻在Threadlocal 中,為什么這么做?

安琪拉:我們看下ThreadlocalMap的說明

  1. class ThreadLocalMap 
  2. * ThreadLocalMap is a customized hash map suitable only for 
  3. * maintaining thread local valuesNo operations are exported 
  4. * outside of the ThreadLocal class. The class is package private to 
  5. * allow declaration of fields in class Thread.  To help deal with 
  6. * very large and long-lived usages, the hash table entries use 
  7. * WeakReferences for keys. However, since reference queues are not 
  8. * used, stale entries are guaranteed to be removed only when 
  9. * the table starts running out of space

大概意思是ThreadLocalMap 就是為維護線程本地變量而設計的,只做這一件事情。

這個也是為什么 ThreadLocalMap 是Thread的成員變量,但是卻是Threadlocal 的內部類(非public,只有包訪問權限,Thread和Threadlocal都在java.lang 包下),就是讓使用者知道ThreadLocalMap就只做保存線程局部變量這一件事的。

面試官:既然是線程局部變量,那為什么不用線程對象(Thread對象)作為key,這樣不是更清晰,直接用線程作為key獲取線程變量?

安琪拉:這樣設計會有個問題,比如: 我已經把用戶信息存在線程變量里了,這個時候需要新增加一個線程變量,比方說新增用戶地理位置信息,我們ThreadlocalMap 的key用的是線程,再存一個地理位置信息,key都是同一個線程(key一樣),不就把原來的用戶信息覆蓋了嘛。Map.put(key,value) 操作熟悉吧,所以網上有些文章說ThreadlocalMap使用線程作為key是瞎扯的。

面試官:那新增地理位置信息應該怎么做?

安琪拉:新創建一個Threadlocal對象就好了,因為ThreadLocalMap的key是Threadlocal 對象,比如新增地理位置,我就再 Threadlocal < Geo> geo = new Threadlocal(), 存放地理位置信息,這樣線程的ThreadlocalMap里面會有二個元素,一個是用戶信息,一個是地理位置。

面試官:ThreadlocalMap 是什么數據結構實現的?

安琪拉:跟HashMap 一樣,也是數組實現的。

代碼如下:

  1. class ThreadLocalMap { 
  2.  //初始容量 
  3.  private static final int INITIAL_CAPACITY = 16; 
  4.  //存放元素的數組 
  5.  private Entry[] table
  6.  //元素個數 
  7.  private int size = 0; 

table 就是存儲線程局部變量的數組,數組元素是Entry類,Entry由key和value組成,key是Threadlocal對象,value是存放的對應線程變量

我們前面舉得例子,數組存儲結構如下圖:

面試官:ThreadlocalMap 發生hash沖突怎么辦?跟HashMap 有什么區別?

安琪拉:【心想】第一次碰到有問ThreadlocalMap哈希沖突的,這個面試越來越有意思了。

說道:有區別的,對待哈希沖突,HashMap采用的鏈表 + 紅黑樹的形式,如下圖,鏈表長度過長(>8) 就會轉成紅黑樹:

ThreadlocalMap既沒有鏈表,也沒有紅黑樹,采用的是鏈地址法, 鏈地址法就是如果發生沖突,ThreadlocalMap直接往后找相鄰的下一個節點,如果相鄰節點為空,直接存進去,如果不為空,繼續往后找,直到找到空的,把元素放進去,或者元素個數超過數組長度閾值,進行擴容。

如下圖:還是以之前的例子講解,ThreadlocalMap 數組長度是4,現在存地理位置的時候發生hash沖突(位置1已經有數據),那就把往后找,發現2 這個位置為空,就直接存放在2這個位置。

源代碼(如果閱讀起來困難,可以看完后文回過頭來閱讀):

  1. private void set(ThreadLocal<?> key, Object value) { 
  2.   Entry[] tab = table
  3.   int len = tab.length; 
  4.   // hashcode & 操作其實就是 %數組長度取余數,例如:數組長度是4,hashCode % (4-1) 就找到要存放元素的數組下標 
  5.   int i = key.threadLocalHashCode & (len-1); 
  6.  
  7.   //找到數組的空槽(=null),一般ThreadlocalMap存放元素不會很多 
  8.   for (Entry e = tab[i]; 
  9.        e != null; //找到數組的空槽(=null) 
  10.        e = tab[i = nextIndex(i, len)]) { 
  11.     ThreadLocal<?> k = e.get(); 
  12.  
  13.     //如果key值一樣,算是更新操作,直接替換 
  14.     if (k == key) { 
  15.       e.value = value; 
  16.       return
  17.     } 
  18.   //key為空,做替換清理動作,這個后面聊WeakReference的時候講 
  19.     if (k == null) { 
  20.       replaceStaleEntry(key, value, i); 
  21.       return
  22.     } 
  23.   } 
  24.  //新new一個Entry 
  25.   tab[i] = new Entry(key, value); 
  26.   //數組元素個數+1 
  27.   int sz = ++size
  28.   //如果沒清理掉元素或者存放元素個數超過數組閾值,進行擴容 
  29.   if (!cleanSomeSlots(i, sz) && sz >= threshold) 
  30.     rehash(); 
  31.  
  32. //順序遍歷 +1 到了數組尾部,又回到數組頭部(0這個位置) 
  33. private static int nextIndex(int i, int len) { 
  34.   return ((i + 1 < len) ? i + 1 : 0); 
  35.  
  36. // get()方法,根據ThreadLocal key獲取線程變量 
  37. private Entry getEntry(ThreadLocal<?> key) { 
  38.   //計算hash值 & 操作其實就是 %數組長度取余數,例如:數組長度是4,hashCode % (4-1) 就找到要查詢的數組地址 
  39.   int i = key.threadLocalHashCode & (table.length - 1); 
  40.   Entry e = table[i]; 
  41.   //快速判斷 如果這個位置有值,key相等表示找到了,直接返回 
  42.   if (e != null && e.get() == key
  43.     return e; 
  44.   else 
  45.     return getEntryAfterMiss(key, i, e); //miss之后順序往后找(鏈地址法,這個后面再介紹) 

面試官:我看你最前面圖中畫的ThreadlocalMap 中key是 WeakReference類型,能講講Java中有幾種類似的引用,什么區別嗎?

安琪拉:可以

  • 強引用是使用最普遍的引用。如果一個對象具有強引用,那垃圾回收器絕不會回收它,當內存空間不足時,Java虛擬機寧愿拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具有強引用的對象來解決內存不足的問題。
  • 如果一個對象只具有軟引用,則內存空間充足時,垃圾回收器就不會回收它;如果內存空間不足了,就會回收這些對象的內存。
  • 弱引用與軟引用的區別在于:只具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描內存區域時,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。不過,由于垃圾回收器是一個優先級很低的線程,因此不一定會很快發現那些只具有弱引用的對象。
  • 虛引用顧名思義,就是形同虛設。與其他幾種引用都不同,虛引用并不會決定對象的生命周期。如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。

妥妥的八股文啊!尷尬(─.─|||。

面試官:那你能講講為什么ThreadlocalMap 中key 設計成 WeakReference(弱引用)類型嗎?

安琪拉:可以的,為了盡最大努力避免內存泄漏。

面試官:能詳細講講嗎?為什么是盡最大努力,你前面也講被WeakReference 引用的對象會直接被GC(內存回收器) 回收,為什么不是直接避免了內存泄漏呢?

安琪拉:我們還是看下下面這張圖:

  1. private static final ThreadLocal<UserInfo> userInfoThreadLocal = new ThreadLocal<>(); 
  2. userInfoThreadLocal.set(userInfo); 

這里的引用關系是userInfoThreadLocal 引用了ThreadLocal對象,這是個強引用,ThreadLocal對象同時也被ThreadlocalMap的key引用,這是個WeakReference引用,我們前面說GC要回收ThreadLocal對象的前提是它只被WeakReference引用,沒有任何強引用。

為了方便大家理解弱引用,我寫了段Demo程序

  1. public static void main(String[] args) { 
  2.   Object angela = new Object(); 
  3.   //弱引用 
  4.   WeakReference<Object> weakReference = new WeakReference<>(angela); 
  5.   //angela和弱引用指向同一個對象 
  6.   System.out.println(angela);//java.lang.Object@4550017c 
  7.   System.out.println(weakReference.get());//java.lang.Object@4550017c  
  8.   //將強引用angela置為null,這個對象就只剩下弱引用了,內存夠用,弱引用也會被回收 
  9.   angela = null;  
  10.   System.gc();//內存夠用不會自動gc,手動喚醒gc 
  11.   System.out.println(angela);//null 
  12.   System.out.println(weakReference.get());//null 

可以看到一旦一個對象只被弱引用引用,GC的時候就會回收這個對象。

所以只要ThreadLocal對象如果還被 userInfoThreadLocal(強引用) 引用著,GC是不會回收被WeakReference引用的對象的。

面試官:那既然ThreadLocal對象有強引用,回收不掉,干嘛還要設計成WeakReference類型呢?

安琪拉:ThreadLocal的設計者考慮到線程往往生命周期很長,比如經常會用到線程池,線程一直存活著,根據JVM 根搜索算法,一直存在 Thread -> ThreadLocalMap -> Entry(元素)這樣一條引用鏈路, 如下圖,如果key不設計成WeakReference類型,是強引用的話,就一直不會被GC回收,key就一直不會是null,不為null Entry元素就不會被清理(ThreadLocalMap是根據key是否為null來判斷是否清理Entry)

所以ThreadLocal的設計者認為只要ThreadLocal 所在的作用域結束了工作被清理了,GC回收的時候就會把key引用對象回收,key置為null,ThreadLocal會盡力保證Entry清理掉來最大可能避免內存泄漏。

來看下代碼:

  1. //元素類 
  2. static class Entry extends WeakReference<ThreadLocal<?>> { 
  3.   /** The value associated with this ThreadLocal. */ 
  4.   Object value; //key是從父類繼承的,所以這里只有value 
  5.  
  6.   Entry(ThreadLocal<?> k, Object v) { 
  7.     super(k); 
  8.     value = v; 
  9.   } 
  10.  
  11. //WeakReference 繼承了Reference,key是繼承了范型的referent 
  12. public abstract class Reference<T> { 
  13.   //這個就是被繼承的key 
  14.   private T referent;  
  15.   Reference(T referent) { 
  16.     this(referent, null); 
  17.   } 

Entry 繼承了WeakReference類,Entry 中的 key 是WeakReference類型的,在Java 中當對象只被 WeakReference 引用,沒有其他對象引用時,被WeakReference 引用的對象發生GC 時會直接被回收掉。

面試官:那如果Threadlocal 對象一直有強引用,那怎么辦?豈不是有內存泄漏風險。

安琪拉:最佳實踐是用完手動調用remove函數。

我們看下源碼:

  1. class Threadlocal { 
  2.   public void remove() { 
  3.       //這個是拿到線程的ThreadLocalMap 
  4.       ThreadLocalMap m = getMap(Thread.currentThread()); 
  5.       if (m != null
  6.         m.remove(this); //this就是ThreadLocal對象,移除,方法在下面 
  7.   } 
  8.  
  9. class ThreadlocalMap { 
  10.   private void remove(ThreadLocal<?> key) { 
  11.     Entry[] tab = table
  12.     int len = tab.length; 
  13.     //計算位置 
  14.     int i = key.threadLocalHashCode & (len-1); 
  15.     for (Entry e = tab[i]; 
  16.          e != null
  17.          e = tab[i = nextIndex(i, len)]) { 
  18.       //清理 
  19.       if (e.get() == key) { 
  20.         e.clear(); 
  21.         expungeStaleEntry(i); //清理空槽 
  22.         return
  23.       } 
  24.    } 
  25.  } 
  26.  
  27. //這個方法就是做元素清理 
  28. private int expungeStaleEntry(int staleSlot) { 
  29.   Entry[] tab = table
  30.   int len = tab.length; 
  31.  
  32.   //把staleSlot的value置為空,然后數組元素置為空 
  33.   tab[staleSlot].value = null
  34.   tab[staleSlot] = null
  35.   size--; //元素個數-1 
  36.  
  37.   // Rehash until we encounter null 
  38.   Entry e; 
  39.   int i; 
  40.   for (i = nextIndex(staleSlot, len); 
  41.        (e = tab[i]) != null
  42.        i = nextIndex(i, len)) { 
  43.     ThreadLocal<?> k = e.get(); 
  44.     //k 為null代表引用對象被GC回收掉了 
  45.     if (k == null) { 
  46.       e.value = null
  47.       tab[i] = null
  48.       size--; 
  49.     } else { 
  50.       //因為元素個數減少了,就把后面的元素重新hash 
  51.       int h = k.threadLocalHashCode & (len - 1); 
  52.       //hash地址不相等,就代表這個元素之前發生過hash沖突(本來應該放在這沒放在這), 
  53.       //現在因為有元素被移除了,很有可能原來沖突的位置空出來了,重試一次 
  54.       if (h != i) { 
  55.         tab[i] = null
  56.  
  57.         //繼續采用鏈地址法存放元素 
  58.         while (tab[h] != null
  59.           h = nextIndex(h, len); 
  60.         tab[h] = e; 
  61.       } 
  62.     } 
  63.   } 
  64.   return i; 

面試官:你有沒有用Threadlocal的工程實際經歷,給我講講。

安琪拉:有啊!

之前我跟你們一面面試官聊過,我是怎么把支付寶后臺負責的系統四十幾個核心rpc接口性能大幅度提升的,下面這個就是其中一個接口切流之后的效果,其中就用到了Threadlocal。圖片

 

面試官:嗯,說說。

安琪拉:我剛才說有四十多個接口要做技改優化,那風險是很高的,我需要保證接口切換后業務不受影響,也叫等效切換。

流程是這樣的:

  • 把這四十多個接口按照業務含義定義了接口常量名稱,比如接口名alipay.quickquick.follow.angela;
  • 按照接口的流量從低到高開始切流,提前配置中心配置好每個接口的切流比例和用戶白名單;
  • 切流也有講究,先按照userId白名單切,再按照userId尾號切百分比,完全沒問題再完整切;
  • 在頂層抽象模版方法的入口通過ThreadLocal Set 接口名,把接口名塞進去;

然后我在切流的地方通過ThreadLocal 獲取接口名,用于接口切流判斷切流;

面試官:最后一個問題,如果我有很多變量都要塞到ThreadlocalMap中,那豈不是要申明很多個Threadlocal 對象?有沒有好的解決辦法。

安琪拉:我們的最佳實踐是搞個再封裝一下,把ThreadLocalMap 的value 弄成Map就好了,這樣只要一個Threadlocal 對象就好了。

面試官:能詳細講講嗎?

安琪拉:講不動了,太累了。

面試官:講講。

安琪拉:真不想講了。

面試官:那今天先到這,您出了這個門右拐,回去等通知吧! 

 

責任編輯:武曉燕 來源: 安琪拉的博客
相關推薦

2024-09-24 10:28:22

2020-04-20 13:11:21

HashMap底層存儲

2025-11-11 09:25:19

2022-04-08 08:26:03

JavaHTTP請求

2025-10-20 04:00:00

2021-09-28 13:42:55

Chrome Devwebsocket網絡協議

2022-08-18 20:02:04

JSLRU緩存

2020-06-22 07:47:46

提交面試官訂單

2022-01-10 11:04:41

單鏈表面試編程

2021-05-19 08:17:35

秒殺場景高并發

2020-05-13 14:35:47

HashMap面試官Java

2023-07-31 08:26:09

2024-02-04 16:14:38

線程開發

2017-03-16 15:27:10

面試官測試技術

2025-09-19 09:57:46

2024-05-28 10:14:31

JavaScrip模板引擎

2021-11-30 08:26:22

ThreadLocal內存飆升存儲模型

2024-08-07 08:15:47

2025-06-04 03:15:00

高并發短鏈系統

2021-06-09 07:55:19

NodeEventEmitte驅動
點贊
收藏

51CTO技術棧公眾號

成人激情自拍| 成年人网站在线| 日韩五码在线| 精品五月天久久| chinese少妇国语对白| 亚洲麻豆精品| 99re在线视频这里只有精品| 国产国语videosex另类| 91麻豆免费视频网站| 美女久久精品| 在线视频你懂得一区二区三区| 亚洲一区三区视频在线观看| 亚洲国产精彩视频| 久久在线精品| 欧美日韩国产成人在线观看| 欧美多人猛交狂配| 精品一区二区三区免费看| 欧美日韩国产综合新一区 | 又骚又黄的视频| 狠狠色丁香久久综合频道| 一本色道久久综合狠狠躁篇的优点| www.久久com| 成人免费网站www网站高清| 一区二区三区精品视频| 三区精品视频观看| 色呦呦视频在线| 国产精品一区二区三区99| 日本久久亚洲电影| av资源吧首页| 欧美.日韩.国产.一区.二区| 国产一区二区欧美日韩| 一区二区三区少妇| 榴莲视频成人app| 欧美日韩国产区一| 欧美 日韩 国产 激情| a在线免费观看| 国产日产精品一区| 高清国产在线一区| 精品国产乱码一区二区三| 青椒成人免费视频| 国产精品99一区| 三级视频在线观看| 亚洲欧美日韩精品一区二区| 欧美日韩国产91| 69av视频在线| 国产一区视频在线观看免费| 久久精品91久久香蕉加勒比| 特级西西人体高清大胆| 不卡一区2区| 一区二区三区视频免费| 国产精品无码久久久久一区二区| 群体交乱之放荡娇妻一区二区| 精品久久国产97色综合| 国产精品无码自拍| 日韩一级淫片| 亚洲成人黄色网址| 国产一卡二卡三卡四卡| 国产一区福利| 日韩黄色高清视频| www.色多多| jiujiure精品视频播放| 中文字幕日韩av电影| 黄色av片三级三级三级免费看| 日本成人小视频| 久久精品国产成人| 欧美成人三级视频| 精品成人国产| 欧美专区福利在线| 91视频在线视频| 久久黄色级2电影| 91久久在线播放| 蜜桃视频久久一区免费观看入口| 成人国产视频在线观看| 精品视频一区在线| 成人免费视频| 一区二区三区资源| 69堂免费视频| 欧美视频第一| 精品欧美一区二区久久| 99久久国产精| 成人高清av| 九九热精品视频在线播放| 久久精品国产亚洲av高清色欲| 亚洲免费观看| 91精品国产综合久久香蕉最新版| 精品女同一区二区三区| 91天堂素人约啪| 天堂一区二区三区| 日本动漫同人动漫在线观看| 欧美性猛交xxx| 黑森林精品导航| 7777精品| 中文字幕国产亚洲2019| 欧美片一区二区| 天堂蜜桃一区二区三区| 亚洲一区二区久久久久久| 四虎影院在线域名免费观看| 国产精品美女www爽爽爽| 欧美久久久久久久久久久久久久| 午夜日韩成人影院| 日韩欧美中文字幕精品| 国产小视频自拍| 欧美午夜不卡| 国产精品三级在线| 色丁香婷婷综合久久| 中国av一区二区三区| 精品成在人线av无码免费看| 亚洲天堂1区| 欧美精品一区二区三区久久久 | 亚洲爱爱综合网| 国产午夜精品一区二区三区四区| 台湾无码一区二区| 精品欧美一区二区三区在线观看 | 中文在线观看免费视频| 日韩在线观看| 日韩免费精品视频| 国产成人三级在线观看视频| 国产精品久久久久久久久搜平片 | 亚洲一区二区精品| 国产无码精品一区二区| 激情欧美一区二区三区在线观看| 蜜桃麻豆www久久国产精品| 欧美aaaaaaa| 91精品国产综合久久久久久漫画| 国产精品815.cc红桃| 亚洲婷婷在线| 91文字幕巨乱亚洲香蕉| 老司机免费在线视频| 在线视频一区二区三区| 成人影视免费观看| 亚洲激情亚洲| 国产成人免费观看| 最新超碰在线| 3751色影院一区二区三区| av电影网站在线观看| 亚洲综合日韩| 欧美精品与人动性物交免费看| 欧美性video| 日韩欧美一级二级三级| 日韩成人短视频| 精品一区二区三区在线播放视频 | 大尺度做爰床戏呻吟舒畅| 欧美激情第10页| 亚洲a∨日韩av高清在线观看| 永久免费在线观看视频| 欧美日韩成人在线一区| 久久久精品成人| 奇米在线7777在线精品 | 夜间精品视频| 91九色蝌蚪国产| 1区2区3区在线视频| 欧美一区二区三区视频免费播放| 91精品一区二区三区蜜桃| 激情亚洲综合在线| 超碰97在线看| 日韩影片在线观看| 欧美国产日韩中文字幕在线| 亚洲精品国产精品国| 亚洲国产中文字幕在线视频综合| 亚洲国产精品第一页| 日韩午夜在线电影| 麻豆传媒一区二区| 亚洲精品555| 日韩视频第一页| 国产视频在线一区| 亚洲自拍与偷拍| 蜜臀av一区二区三区有限公司| 裸体一区二区| 一区二区三区四区国产| 久久国产精品美女| 97在线视频免费看| 黄色av网站在线看| 欧美理论电影在线| xxxx 国产| 国产亚洲精品7777| 国产精欧美一区二区三区白种人| 午夜亚洲福利| 免费在线成人av电影| 99热播精品免费| 欧美国产日韩视频| 黄色片在线免费观看| 欧美一区二区三区色| 九九视频免费观看| 久久综合九色欧美综合狠狠| 亚洲国产精品三区| 欧美精品色网| 日本一区二区三区免费观看| 国产aa精品| 欧美影院久久久| 男女啪啪在线观看| 亚洲精品白浆高清久久久久久| 国产乡下妇女三片| 亚洲一二三区在线观看| 手机毛片在线观看| 成人免费视频网站在线观看| av丝袜天堂网| 激情欧美一区| 一区一区视频| 一本色道久久综合亚洲精品酒店| 成人女保姆的销魂服务| 免费在线小视频| 美女视频久久黄| 成年人视频网站在线| 亚洲国产精品女人久久久| 中文字幕在线观看精品| 精品国产91久久久久久老师| 亚洲色偷偷综合亚洲av伊人| 久久综合久久99| 好男人香蕉影院| 国产自产2019最新不卡| 色婷婷综合久久久久中文字幕| 欧美性久久久| 黄色a级在线观看| 精品国产乱码久久久久久1区2匹| 国产精品美女诱惑| 伊人久久大香线蕉综合影院首页| 日本a级片电影一区二区| 久久亚洲资源| 蜜月aⅴ免费一区二区三区| 国产福利小视频在线观看| 亚洲国产毛片完整版| 国产丝袜视频在线观看| 欧美日本在线一区| 欧美成人一区二区三区四区| 亚洲国产一区在线观看| 国产极品国产极品| 中文字幕一区二区5566日韩| 日本乱子伦xxxx| 久久久一区二区三区捆绑**| 国产chinese中国hdxxxx| 国产福利一区二区三区视频在线| 亚洲精品性视频| 久久国产综合精品| mm131亚洲精品| 日本欧美在线观看| 黄色一级片播放| 亚洲精选一区| 男人日女人视频网站| 很黄很黄激情成人| 欧美黑人在线观看| 欧美精品国产一区| 成人短视频在线观看免费| 女生裸体视频一区二区三区| 女女同性女同一区二区三区按摩| 日韩视频在线观看| 午夜午夜精品一区二区三区文| 欧美精品尤物在线观看 | 欧美精品网站| 久久久无码中文字幕久...| 亚洲一区 二区 三区| 九九久久九九久久| 欧美视频二区| 成人一级生活片| 在线一区免费观看| 女人扒开屁股爽桶30分钟| www.好吊色| 91在线看国产| 一区二区精品免费| 中文无字幕一区二区三区 | 国产精品第100页| 日韩免费小视频| 国产日韩欧美影视| 99视频有精品高清视频| 91丨九色丨国产| 欧美一性一交| 日韩av电影在线观看| 久久亚洲精品中文字幕蜜潮电影| 亚洲 欧洲 日韩| 国产精品九九| wwwxxx黄色片| 快she精品国产999| 免费精品99久久国产综合精品应用| 国产一区二区剧情av在线| 亚洲一区和二区| 91在线精品一区二区| 欧美波霸videosex极品| 亚洲欧美另类图片小说| 日本五十路女优| 欧美在线观看一区二区| 99在线观看免费| 亚洲精品国产欧美| 91caoporm在线视频| 九九综合九九综合| 欧美黑人疯狂性受xxxxx野外| 成人激情av在线| youjizzjizz亚洲| 色一情一区二区三区四区| 在线成人超碰| 北条麻妃在线一区| 国产精品一区二区久久不卡| 国产精品jizz| 亚洲少妇30p| 黄色一级视频免费看| 欧美国产极品| 91亚洲国产成人精品性色| 网红女主播少妇精品视频| 一区二区三区四区不卡| 一区二区三区四区五区精品视频| 天天干天天操天天做| aaa亚洲精品| 日本在线一级片| 欧洲中文字幕精品| 你懂的网站在线| 久久夜色撩人精品| 欧美成人免费电影| 国产精品嫩草在线观看| 欧美独立站高清久久| 欧美v在线观看| 国产成人av影院| 少妇的滋味中文字幕bd| 欧美日韩国产在线看| 国产草草影院ccyycom| 国产一区二区欧美日韩| 国产在线88av| 91免费在线观看网站| 成人激情诱惑| www.com毛片| 成人sese在线| 青青草手机在线视频| 欧美高清hd18日本| 最新电影电视剧在线观看免费观看| 午夜精品美女自拍福到在线| 国产精品久久免费视频| 亚洲精品中字| 日韩av不卡一区二区| 色婷婷av777| 成人在线中文| 精品国产乱码久久久久久丨区2区| 五月精品视频| 亚洲综合日韩欧美| 国产日韩欧美一区二区三区综合| 久久精品欧美一区二区| 欧美一区二区视频网站| 欧美精品日韩少妇| 国产精品日韩精品| 国产亚洲一区二区三区不卡| 免费高清在线观看免费| 99久久精品国产一区| www.天天色| 亚洲国产成人精品一区二区| 国产一线二线在线观看| 国产高清精品一区二区| 欧美精品99| 亚洲麻豆一区二区三区| 亚洲一区二区三区四区在线| 亚洲风情第一页| 亚洲91精品在线观看| 成人偷拍自拍| 欧美日韩在线一| 久久综合久久综合亚洲| 福利网址在线观看| 伊人久久大香线蕉av一区二区| 日韩中文视频| 制服国产精品| 国产精一品亚洲二区在线视频| 欧美成人三级在线观看| 欧美精品一区二| 中文字幕在线中文字幕在线中三区| 精品欧美国产| 日韩电影在线一区二区| аⅴ天堂中文在线网| 777午夜精品视频在线播放| 亚洲制服国产| 国产伦理一区二区三区| 香蕉久久夜色精品| 日本精品久久久久中文| 337p亚洲精品色噜噜| 久久婷婷综合国产| 久久国产人妖系列| 中文字幕在线免费看线人| 91福利在线免费观看| 男人天堂久久久| 国产精品手机在线| 久久精品道一区二区三区| 国产精品一区二区亚洲| 日韩欧美一二区| 91久久国产综合久久91猫猫| 亚洲国产精品视频一区| 国产精品18久久久久| 亚洲日本视频在线观看| 日韩中文第一页| 国产精品男女| 九九九在线观看视频| 夜夜嗨av一区二区三区中文字幕| 天堂成人在线| 91网站在线免费观看| 中文一区在线| 熟女少妇a性色生活片毛片| 亚洲国产精品人人爽夜夜爽| a屁视频一区二区三区四区| 男人添女荫道口喷水视频| 亚洲国产高清在线| 亚洲毛片欧洲毛片国产一品色| 国产精品96久久久久久| 午夜精品久久久久99热蜜桃导演 | 亚洲日产av中文字幕| 在线免费看污网站| 日韩欧美aaa| 青草视频在线免费直播| 视频一区二区三|