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

面試中如何答好:AQS

開發 前端
我們知道synchronized是不可中斷的鎖,當線程因為競爭資源失敗而進入阻塞狀態后,唯一能讓該線程結束阻塞的方式就是持有鎖資源的線程處理完成后,被阻塞的線程被喚醒。

本篇內容基本已經涵蓋了AQS的全部核心內容,本篇相比于上一篇補充了“中斷”。

前置思考

實現鎖應該考慮的問題

  1. 如何獲取資源(鎖)?
  2. 獲取不到資源的線程如何處理?
  3. 如何釋放資源?
  4. 資源釋放后如何讓其他線程獲取資源?

由此可以得出實現一把鎖,應該具備哪些邏輯

  • 鎖的標識
    需要有個標識或者狀態來表示鎖是否已經被占用。
  • 線程搶鎖的邏輯
    多個線程如何搶鎖,如何才算搶到鎖,已經搶到鎖的線程再次搶鎖如何處理等等。
  • 線程掛起的邏輯
    線程如果搶到鎖自然順利往下運行了,而那些沒有搶到鎖的線程怎么處理呢?如果一直處于活躍狀態,cpu肯定是吃不消,那就需要掛起。具體又如何掛起呢?
  • 線程存儲機制
    沒有搶到鎖的線程就掛起了,而且被掛起的線程可能有很多個,這些線程總要放在某個地方保存起來等待喚醒,然而這么多被掛起的線程,要喚醒哪一個呢?這就需要一套保存機制來支撐喚醒邏輯。
  • 線程釋放鎖的邏輯
    線程在執行完后就要釋放鎖,跟搶鎖邏輯是對應的,其實也是操作鎖標識。
  • 線程喚醒的邏輯
    鎖釋放后,就要去喚醒被阻塞的線程,這就要考慮喚醒誰,如何喚醒,喚醒后的線程做什么事情。

帶著上面的思考,我們來看看AQS是怎么處理的

AQS由來

在最早期java中的同步機制是通過關鍵字synchronized實現,這個鎖是java原生的,jvm層面實現的。在1.6之前synchronized的性能比較低,是一把純重量級鎖。

后來,Doug Lea開發并引入了java.util.concurrent包,這個包基本涵蓋了java并發操作的半壁江山,該包內的并發工具類基本是以AQS為基礎的,AQS提高了同步操作的性能,在性能上遠超當時的synchronized,后來synchronized做了優化,java1.6及之后兩者的性能就差不多了。

AQS是什么

AQS的全稱為AbstractQueuedSynchronizer

AQS其實是一個抽象類,它實現了線程掛起的邏輯,實現了線程存儲機制,實現了鎖的狀態邏輯,實現了線程喚醒的邏輯,卻只定義了線程搶鎖和釋放鎖的抽象,這樣做的目的是將搶鎖和釋放鎖的邏輯交給子類來實現,這樣有助于實現各種不同特性的鎖,比如共享鎖,獨占鎖,公平鎖,非公平鎖,可重入等。并且以模板方法模式將上述上鎖流程和釋放鎖流程封裝為固定模板方法。所以AQS就是一個多線程訪問共享資源的同步器框架。

AQS實現同步機制有兩種模式,一種是獨占模式,一種是共享模式。兩種模式分別提供提供兩個模板方法實現。四個模板方法為acquire,release,acquireShared,releaseShared。

獨占模式的鎖是只允許一個線程持有鎖

共享模式的鎖是允許多余一個的線程持有鎖

接下來分別介紹這四個方法的邏輯

acquire方法解析

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
}

acquire方法是獨占模式上鎖的整個邏輯,這個方法是一個模板方法,其中的tryAcquire是獲取鎖的邏輯,這個方法是一個抽象方法,由具體的子類實現,如何獲取鎖,怎樣才算獲取到鎖這些問題子類自己決定,AQS不做處理。

addWaiter方法負責是線程存儲的邏輯,aqs里面存儲機制的核心是兩個隊列,等待隊列和條件隊列,它們用來保存被阻塞的線程,在這個方法中通過cas+自旋的方式將線程添加到等待隊列中。

先來介紹等待隊列,等待隊列的結構如下:

圖片圖片

等待隊列是一個雙向鏈表,每個節點就是一個node對象,node是aqs類中的一個靜態內部類,它的屬性如下:

node{thread;prev;next;nextWaiter;waitStatus;}

thread是當前node節點所綁定的線程;

prev是前置節點的引用;

next是后置節點的引用;

nextWaiter如果是等待隊列節點就標示獨占模式節點還是共享模式,如果是條件隊列節點就作為后置節點指針;

waitStatus是節點的狀態,其狀態值如下:

  • static final int CANCELLED =  1; 出現異常
  • static final int SIGNAL    = -1;可被喚醒
  • static final int CONDITION = -2; 條件等待
  • static final int PROPAGATE = -3;傳播

AQS類自身也有幾個比較重要的屬性

//正在持有鎖的線程
private transient Thread exclusiveOwnerThread;
//等待隊列的頭節點
private transient volatile Node head;
//等待隊列的尾節點
private transient volatile Node tail;
//鎖標識字段
private volatile int state;

了解了等待隊列,接下來具體看看addWaiter方法的邏輯

  1. 首先如果隊列還沒有初始化會先初始化隊列,初始化就是先創建一個空的node節點,把aqs里面的head和tail屬性指向這個空的node,初始化完成;

圖片圖片

  1. 先創建一個node節點,默認屬性如下:

node{ thread=當前線程t1;prev;next;nextWaiter=獨占模式;waitStatus=0}

開始入隊操作,入隊就是cas+自旋的方式將tail指針指向新加入的node節點,并且把新加入的node和head建立雙向指針。

圖片圖片

cas是保證原子性的,多線程操作的情況下,當前線程可能會操作失敗,自旋是為了失敗重試,保證一定能夠入隊成功。

入隊成功后,就要掛起線程了,acquireQueued方法就是掛起操作。

這個方法比較核心,線程掛起的邏輯和線程喚醒后的邏輯都在此方法中,源碼如下:

final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

邏輯解析:

  1. 開啟for循環,讓線程處于循環中
  2. node節點已經入隊,先拿到node節點的前置節點,然后做如下判斷
if (p == head && tryAcquire(arg))

上面介紹了等待隊列,等待隊列的head節點永遠是一個不綁定線程的節點,所以拿到前置節點后判斷是否為head節點,如果為head節點才有資格再次獲取鎖,可以發現如果隊列中已經有其他線程處于阻塞等待狀態,新入隊線程是在這個判斷中永遠會返回fasle。

這個判斷加在這里有什么用處呢?

有兩個用處:第一個是入隊后掛起前這個時間段中,可能鎖已經被釋放了,所以這里再次嘗試獲取鎖,這樣就不用阻塞掛起了;第二個用處是,這個判斷處于循環中,阻塞掛起的動作也是在循環中,當被喚醒后,線程會從被掛起的點繼續運行,會再次進入這個判斷,從而實現被喚醒的線程再次嘗試換取鎖的邏輯。

  1. 如果沒有獲取到鎖,那接下來就會進入這個方法shouldParkAfterFailedAcquire,這個方法的源碼如下
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            return true;
        if (ws > 0) {
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
    compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

代碼邏輯為:獲取node節點的前置節點的waitStatus屬性;

如果waitStatus為-1返回true;

如果waitStatus>0,根據waitStatus狀態可知,大于0的只有1,1代表線程被取消或者線程異常,所以這里的做法是將異常的node節點從隊列中移除,采用的方式為從尾節點開始向前遍歷判斷移除,直到遇到一個非異常節點。返回false。

如果waitStatus小于-1,那就把waitStatus通過cas改為-1,返回false。

如果此方法返回false,因為當前處在循環中,所以會再次進入此方法,此時一定會返回true。

只有將當前node節點的前置節點設置為-1后,此方法才會返回true,從而會進入后面的parkAndCheckInterrupt()方法,這個方法就很簡單了,就是調用LockSupport類的park方法將線程阻塞掛起。

private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
 }

為什么在阻塞前一定要將當前node節點的前置節點置為-1?

waitStatus為-1代表可喚醒狀態,獨占模式下,AQS在喚醒被阻塞線程的時候,總是通過判斷head節點的waitStatus狀態,如果為可喚醒狀態代表head后面的節點可以被喚醒,否則不允許喚醒。

這樣做的好處是,當head節點后面線程獲取到鎖并出隊后,可以直接將head指針移動到第一個線程節點,然后將此節點上的前置指針刪除,將線程屬性刪除,作為新的head節點。

圖片圖片

當線程調用park方法后,線程就阻塞在這里,當被喚醒后,線程也是從這個點繼續往下進行,此時依然處在循環中,這個時候會開始新一輪循環,從而再次進入嘗試獲取鎖的判斷,如果獲取到鎖,就出隊,否則再次進入阻塞掛起的方法進行掛起操作。

這里的設計是先搶鎖,搶到鎖后再出隊,避免在沒有搶到鎖的情況下不用再次入隊造成的時間消耗。

release方法解析

//獨占模式的鎖調用的釋放鎖邏輯    
public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

這個方法也是一個模板方法,tryRelease是釋放鎖的方法,它是抽象方法,具體由子類來實現。

釋放成功后就要喚醒被阻塞的線程,核心邏輯在下面這個方法中,源碼如下:

private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);
            
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }

先看下整體邏輯,這兩段代碼的邏輯其實很簡單:

  1. head節點的waitStatus屬性為-1,才能進入unparkSuccessor進行喚醒邏輯
  2. 在unparkSuccessor方法中首先會將head節點的waitStatus改為0
  3. 取head節點的下一個節點next,要判斷next節點的waitStatus屬性是否大于0,如果大于0表示此節點異?;蛘弑蝗∠麑儆诜钦9濣c,從尾節點向前遍歷直到找到最靠近head節點的正常節點,即為要喚醒的線程。
  4. 最后調用LockSupport.unpark方法喚醒線程。

邏輯很容能看懂,但是這里有個問題,為什么前面有這段代碼

if (h != null && h.waitStatus != 0) 
       unparkSuccessor(h);

后面unparkSuccessor方法又有這一段代碼

if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);

不難看出邏輯是waitStatus不為0進入unparkSuccessor方法,進入方法馬上把waitStatus改為0,這是在阻止后續的線程再進來。

那真正的用意是什么呢?

通過上面代碼可以知道釋放鎖邏輯和喚醒邏輯是分開的,看下面的時間抽

  1. 線程1搶到鎖
  2. 線程1釋放鎖
  3. 線程2搶到鎖
  4. 線程1判斷head節點waitStatus狀態為-1后,進入unparkSuccessor方法執行喚醒操作,該方法第一步是將waitStatus狀態改為0
  5. 線程2釋放鎖
  6. 線程2判斷head節點waitStatus狀態為0后,不會進入unparkSuccessor方法

上面這個場景是非公平鎖的場景,公平鎖說的是所有線程都要按照順序排隊獲取鎖,而非公平鎖說的是新進來的線程可以和剛被喚醒的線程搶鎖。

在非公平鎖的場景中,如果代碼塊中的邏輯執行的足夠快就有可能發生上面的情況,線程1和線程2都是都去喚醒同一個線程,所以這里通過將head節點的waitStatus改為0的方式將其他線程拒之門外,這樣就保證在head節點后面的線程只會由一個線程去喚醒。

acquireShared方法解析

//共享模式的鎖調用的上鎖邏輯   
public final void acquireShared(int arg) {
    if (tryAcquireShared(arg) < 0)
        doAcquireShared(arg);
}

此方法同樣是一個模板方法,tryAcquireShared方法是抽象方法,供子類實現搶鎖的邏輯,doAcquireShared方法則是實現阻塞掛起和入隊,doAcquireShared方法源碼如下:

private void doAcquireShared(int arg) {
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        if (interrupted)
                            selfInterrupt();
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
private void setHeadAndPropagate(Node node, int propagate) {
        Node h = head;
        setHead(node);
      
        if (propagate > 0 || h == null || h.waitStatus < 0 || (h = head) == null || h.waitStatus < 0) {
            Node s = node.next;
            if (s == null || s.isShared())
                doReleaseShared();
        }
    }

通過源碼會發現doAcquireShared這個方法合并了入隊和掛起兩個步驟,整體的邏輯基本和獨占模式一樣,接下來只介紹不同的地方。

第一個不同,入隊的時候創建的node節點為共享模式節點,即nextWaiter屬性的值不同。

第二個不同,獨占模式下線程被喚醒重新獲取到鎖后,就要出隊了,而共享模式下除了出隊,還會判斷是否資源充足,如果充足就喚醒下一個節點。

releaseShared方法解析

//共享模式的鎖調用的釋放鎖的邏輯   
public final boolean releaseShared(int arg) {
      if (tryReleaseShared(arg)) {
          doReleaseShared();
          return true;
      }
      return false;
}

同樣此方法也是模板方法,tryReleaseShared方法是交給子類實現的釋放鎖的邏輯,doReleaseShared方法則是aqs自己實現的喚醒邏輯,喚醒邏輯和獨占模式下的喚醒邏輯大同小異,都是喚醒head節點的下一個節點綁定的線程,不再過多贅述。

總結一下獨占和共享模式在aqs中實現的最大不同是被喚醒的線程出隊后會在資源充足的情況下順便喚醒其后面節點的線程。

AQS中的Condition

上面說過,AQS有兩個隊列,等待隊列和條件隊列,上面介紹了等待隊列,但是條件隊列一直未提,那么條件隊列是做什么的呢?

先說下條件隊列的結構

AQS內部有一個內部類ConditionObject,其內部維護了一個單向鏈表(先進先出),這個內部類內有兩個屬性:firstWaiter和lastWaiter分別指向單向鏈表的頭結點和尾節點,這個單向鏈表就是條件隊列,和等待隊列的不同處是它的頭節點是綁定線程的,條件隊列的結構如下

圖片圖片

這個內部類主要的方法是如下三個,這里直接說每個方法的底層邏輯,源碼就不展示了,可以自己去查閱源碼

首先先說下Condition整體的思維邏輯

  1. 入隊,包括初始化條件隊列,隊列的節點依然是node對象,利用nextWaiter屬性指向下一個節點,waitStatus屬性的值默認為-2,代表等待
  2. 釋放鎖,在入隊后就要釋放鎖了
  3. 阻塞
  4. 條件達成后換隊
  5. 阻塞被喚醒后,按照獨占鎖的方式去再次嘗試搶鎖嗎,這里和獨占模式下的喚醒邏輯是一樣的
  • await()的邏輯
  1. 入隊,包括初始化條件隊列,隊列的節點依然是node對象,利用nextWaiter屬性指向下一個節點,waitStatus屬性的值默認為-2,代表等待
  2. 釋放鎖,在入隊后就要釋放鎖了
  3. 阻塞
  • signal()的邏輯
  1. 條件達成后換隊
  2. 阻塞被喚醒后,按照獨占鎖的方式去再次嘗試搶鎖嗎,這里和獨占模式下的喚醒邏輯是一樣的

條件達成后換隊的意思就是將條件隊里的頭節點移動到獨占模式的等待隊列中去,入隊的方式和獨占模式下入隊方式一樣,入隊之后會將當前節點的前一個節點的waitStatus置為-1,代表可喚醒。

  • signalAll()的邏輯

這個方法和上面的方法一樣,不同點就是此方法是將條件隊列的節點一個一個全部移動到等待隊列上去。

看的出來Condition中的條件隊列依賴等待隊列,具體使用可以參考ReentrantLock。你會發現在ReentrantLock鎖里面使用Condition,就相當于在synchronized代碼塊中使用object類的wait方法和nottfyf。

為了更好的理解Condition,一起看下ArrayBlockingQueue的實現,它是一個數組實現的先進先出的有界阻塞隊列,隊列滿,入隊者等待,隊列空,出隊者等待。

這個隊列有兩個重要的特點:先進先出和隊列有界。

為保證先進先出,需要加鎖處理,獲取到鎖的線程才有資格向隊列中放數據或者取出數據。

那如何保證隊列有界的情況下等待處理呢?這個時候就用到Condition了,它的邏輯是這樣的,所有想向隊列添加數據的和所有想從隊列取數據的線程一起競爭鎖,拿到鎖的那個線程才有資格操作,ArrayBlockingQueue維護里兩個Condition對象,也就相當于維護兩個條件隊列,如果是添加數據的某個線程搶到了鎖,在操作添加的時候,發現隊列已滿,此時該線程無法將數據插進去,需要等待有一個數據被取走后才能做添加操作,但是該線程占有鎖資源,取數據的線程進不來,所以就無法進行下去,ArrayBlockingQueue的做法是將該線程放入條件隊列阻塞掛起,等到有一個數據被取走后,再把條件隊列中的掛起的線程搬運到鎖的等待隊里上去,從而再次獲取排隊搶鎖的資格。

之所以維護兩個Condition條件隊列是為了將添加數據的線程和取數據的線程分開,根據不同的條件操作不同的條件隊列。

有沒有發現,這不就是synchronized代碼塊中的object類的wait方法嗎

但是不同點是調用object類的wait方法阻塞的線程,要么只有一個被釋放,要么全部釋放。

而Condition就不同了,因為你可以聲明多個Condition對象,將不同條件下阻塞的線程放入不同的Condition對象,釋放的時候也按照條件釋放,這就真正意義上實現了按條件釋放。

我說的釋放是重新獲取排隊搶奪資源的資格。

AQS中的中斷

不可中斷說的是阻塞狀態不能被終止。

我們知道synchronized是不可中斷的鎖,當線程因為競爭資源失敗而進入阻塞狀態后,唯一能讓該線程結束阻塞的方式就是持有鎖資源的線程處理完成后,被阻塞的線程被喚醒。

synchronized中的阻塞狀態不可中斷是因為線程的阻塞喚醒是由操作系統來管理,而AQS中的阻塞之所以支持中斷是因為上鎖是通過LockSupport類的park方法來實現的,當線程調用park方法阻塞后,如果調用此線程interrupt方法,阻塞狀態就會中斷,也就是阻塞中的線程會被喚醒。

但是調用acquire上鎖的時候如果沒有獲取到鎖就會被阻塞,此時如果調用被阻塞線程的interrupt方法就會喚醒這個線程,但是此時被喚醒的線程處于循環之中,會重新去搶鎖,如果獲取不到依然會再次阻塞,也就是說acquire方法中被阻塞的線程被中斷后只不過會讓線程提前加入搶鎖,但是并不會增加搶到鎖的概率,因為只有阻塞隊列的頭節點才有資格搶鎖。

這里介紹一個知識點:常見的可中斷方法sleep,wait,park方法,這三個方法都會使得線程處于靜止狀態,此時調用interrupt方法,會中斷其靜止狀態,線程從而處于重新被激活的狀態,不同的是被激活后的線程的中斷狀態是不一樣的,sleep和wait方法被激活后,線程的中斷狀態為false,而park方法被激活后,線程的中斷狀態為true,這是需要注意的。

按照上面的說法AQS雖然支持中斷,但是似乎沒什么用,其實AQS還有一個相對于acquire方法不那么常用的方法tryAcquireNanos方法。

跟一下這個方法進入doAcquireNanos方法,主要邏輯就在這個方法中,其實和tryAcquireNanos和acquire一樣,都是搶鎖,入隊,阻塞,喚醒那一套邏輯。

不同的是tryAcquireNanos方法還具備兩個技能:

  1. 支持指定阻塞時間,一定時間后線程將會自動喚醒,自動喚醒后的線程的中斷狀態為false。
  2. 支持被中斷后拋出異常InterruptedException。
private boolean doAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (nanosTimeout <= 0L)
            return false;
        final long deadline = System.nanoTime() + nanosTimeout;
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return true;
                }
                nanosTimeout = deadline - System.nanoTime();
                if (nanosTimeout <= 0L)
                    return false;
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

上面的代碼可以清楚的看到阻塞操作是通過這段代碼實現:

LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(10));

parkNanos方法相對與park方法的區別就是parkNanos方法可以指定阻塞時間。

而下面這段代碼實現的就是阻塞被中斷的時候主動拋出InterruptedException異常,可以讓方法外部捕獲到這個異常,從而達到真正的阻塞中斷。

if (Thread.interrupted())
                    throw new InterruptedException();


責任編輯:武曉燕 來源: 碼農本農
相關推薦

2023-10-11 08:22:33

線程AQScondition

2023-10-12 08:19:04

Monitor線程

2023-10-09 08:04:52

面試CASABA

2023-10-17 15:56:37

FutureTask線程

2023-10-16 10:09:41

線程進程

2024-06-14 09:53:02

2023-10-29 17:08:38

AQS線程

2020-10-12 18:00:39

JavaAQS代碼

2024-03-06 08:00:56

javaAQS原生

2025-01-13 09:24:32

2024-09-03 07:58:46

2021-03-18 08:04:54

AQS工具CAS

2020-12-01 07:16:05

重學設計模式

2020-01-16 14:59:32

Java鎖優化CAS

2023-10-26 16:02:04

線程

2022-07-06 07:35:19

group byMySQL

2020-10-16 08:26:38

AQS通信協作

2012-08-08 10:00:17

面試技術

2022-09-12 22:27:05

編程式事務聲明式事務對象

2023-04-14 08:39:01

AQS方法JDK5
點贊
收藏

51CTO技術棧公眾號

亚洲女同志freevdieo| 影音先锋黄色网址| 欧美调教网站| 欧美性受极品xxxx喷水| 日本不卡一区二区三区四区| 亚洲精品久久久久久动漫器材一区| 亚洲九九精品| 国产精品丝袜黑色高跟| 久久久久久久久久亚洲| 中文文字幕文字幕高清| 免费看美女视频在线网站| 国产福利一区二区| 日本伊人精品一区二区三区介绍 | 亚洲欧美一区二区激情| 欧美性受xxxxxx黑人xyx性爽| 久久国产精品黑丝| 欧美激情在线一区二区| 99一区二区三区| 精品手机在线视频| av毛片精品| 欧美午夜理伦三级在线观看| 男女日批视频在线观看| 色开心亚洲综合| 久久久影院官网| 不卡一区二区三区四区五区| 91女人18毛片水多国产| 久久综合九色| 性欧美办公室18xxxxhd| 午夜免费激情视频| 日韩精品看片| 亚洲毛片在线观看.| 美女日批在线观看| 黄黄的网站在线观看| 91日韩在线专区| 国产精品青青草| av免费在线观看不卡| 日本欧美一区二区三区| 国产91成人在在线播放| 久久免费公开视频| 国产香蕉精品| 精品免费视频一区二区| 亚洲制服中文字幕| 国产a亚洲精品| 欧美网站大全在线观看| 国产日韩成人内射视频| 东京一区二区| 欧美性极品xxxx做受| 欧美人成在线观看| 青春草免费在线视频| 一区二区三区日韩精品| 伊人再见免费在线观看高清版 | 欧美国产视频一区二区| 极品盗摄国产盗摄合集| 一区二区三区四区电影| 日韩精品一区二区三区在线| 日韩av一卡二卡三卡| 欧美色片在线观看| 国产精品美女www爽爽爽| 欧美三日本三级少妇三99| 日批视频在线播放| 94色蜜桃网一区二区三区| 韩日午夜在线资源一区二区| 三级视频在线看| 91网页版在线| 欧美日韩一区在线视频| а天堂8中文最新版在线官网| 国产婷婷色一区二区三区| 91精品视频免费| 国产偷拍一区二区| 国产不卡免费视频| 国产精品区一区二区三在线播放 | 国产乱码精品一区二区三区亚洲人| 亚洲专区一二三| 久久综合九色综合网站| 大乳在线免费观看| 国产精品乱码一区二三区小蝌蚪| 制服丝袜综合日韩欧美| 26uuu亚洲电影在线观看| 久久综合久久鬼色| 水蜜桃一区二区三区| 色综合久久久久综合一本到桃花网| 国产精品高潮呻吟久久| 欧美lavv| 日本中文字幕在线播放| 亚洲综合色婷婷| 无码精品a∨在线观看中文| free欧美| 日韩欧美一级在线播放| 91av在线免费| 欧美大人香蕉在线| 亚洲人成在线观看网站高清| eeuss中文字幕| 欧美激情成人在线| 日本欧美一二三区| 97免费观看视频| 成人美女视频在线看| 日韩欧美视频一区二区三区四区| 91在线中文| 色综合天天综合在线视频| 国产乱女淫av麻豆国产| 久久国产精品免费精品3p| 国产亚洲精品美女久久久| 麻豆一区产品精品蜜桃的特点| 久久黄色影院| 国产高清在线一区二区| 成年女人的天堂在线| 亚洲一区二区三区四区在线免费观看| 欧美成人黑人猛交| 成人性生交大片免费看中文视频| 一夜七次郎国产精品亚洲| 久草免费在线观看视频| 蜜臀av性久久久久av蜜臀妖精 | 天堂网av手机版| 亚洲性色视频| 国产精品专区一| 深夜福利免费在线观看| 亚洲一二三四在线| 亚洲欧美日本一区二区| 国产一区2区| 97国产真实伦对白精彩视频8| 一区二区三区免费在线| 久久综合五月天婷婷伊人| www.在线观看av| 国产美女视频一区二区 | 黄色免费在线观看| 在线国产电影不卡| 亚洲色精品三区二区一区| 亚洲三级av| 久久亚洲电影天堂| 伊人网综合在线| 久久精品人人做| 成人免费aaa| 91精品入口| 欧美精品免费在线| 91av国产精品| 国产精品久久久久国产精品日日| 日韩视频第二页| 欧美sss在线视频| 91国产中文字幕| 农村少妇久久久久久久| 亚洲线精品一区二区三区八戒| 宇都宫紫苑在线播放| 清纯唯美激情亚洲| 久久精品中文字幕免费mv| 中文字幕观看在线| 亚洲国产精品成人综合| 久久婷婷国产91天堂综合精品| 一区二区三区视频免费观看| 26uuu另类亚洲欧美日本一| 欧美一级性视频| 午夜精品久久久久久久| 国产十八熟妇av成人一区| 国内自拍视频一区二区三区| 成人国产1314www色视频| 免费污视频在线| 精品国产1区2区3区| 国产午夜久久久| www.性欧美| 欧美一级片中文字幕| 国产欧美日韩一区二区三区四区 | 国产一线二线三线女| 伊人久久亚洲| 97超碰国产精品女人人人爽| 天堂中文字幕av| 一道本成人在线| 亚洲精品午夜视频| 蜜桃视频第一区免费观看| 伊人情人网综合| 日韩最新av| 7m精品福利视频导航| 欧美伦理影视网| 欧美视频三区在线播放| 永久免费看片视频教学| 国产成人免费视频一区| 亚洲熟妇国产熟妇肥婆| 精品美女视频| 3d动漫啪啪精品一区二区免费| 国产盗摄一区二区| 亚洲色图25p| 一级特黄aaa大片| 亚洲国产综合人成综合网站| 白丝女仆被免费网站| 美女久久久精品| 日本福利视频在线观看| 亚瑟一区二区三区四区| 国产精品中文字幕在线| 国产美女情趣调教h一区二区| 亚洲欧美国产视频| a在线观看视频| 色网站国产精品| 男人的天堂久久久| 久久亚洲春色中文字幕久久久| 日本黄色福利视频| 一本久久综合| 超碰97在线看| 久久最新网址| 97免费中文视频在线观看| 黄色在线网站| 日韩欧美国产骚| 天天看天天摸天天操| xnxx国产精品| 永久看看免费大片| 久久综合亚州| 日韩国产成人无码av毛片| av亚洲在线观看| 精品高清视频| 亚洲国产aⅴ精品一区二区| 欧洲日韩成人av| 好久没做在线观看| 久久久999精品视频| 欧美成熟毛茸茸| 精品国产髙清在线看国产毛片| 欧美三级网站在线观看| 午夜久久电影网| 欧美激情一区二区视频| 国产精品全国免费观看高清| 800av在线播放| 大美女一区二区三区| 五月婷婷激情久久| 男人的天堂亚洲在线| www.99热这里只有精品| 在线观看免费一区二区| 亚洲精品在线免费| 国产欧美日韩免费观看| 欧美美乳视频网站在线观看| 牛牛精品成人免费视频| 超碰97在线资源| 日日夜夜精品视频| 99se婷婷在线视频观看| 国产一区二区三区| 成人国产精品久久久| 制服丝袜中文字幕在线| 色偷偷av一区二区三区乱| 国内av一区二区三区| 亚洲久久久久久久久久| 天天操天天干天天干| 日韩女同互慰一区二区| 国产免费不卡视频| 777奇米成人网| 国产精品女人久久久| 欧美日韩久久久久久| 国产三级理论片| 欧美午夜电影在线播放| 亚洲一卡二卡在线观看| 欧美日韩国产高清一区二区三区| 在线观看免费中文字幕| 欧美日韩亚洲综合一区二区三区| 中文字幕人成人乱码亚洲电影| 在线观看亚洲精品| 中文有码在线播放| 欧美日韩高清一区二区三区| 亚洲自拍第二页| 欧美精品九九99久久| 国产精品自产拍| 日韩视频在线一区二区| 亚洲精品一区二区三区不卡| 亚洲成年人影院在线| 天天躁日日躁狠狠躁伊人| 精品视频一区在线视频| 国产手机视频在线| 日韩欧美国产精品一区| 黑人乱码一区二区三区av| 在线观看日韩精品| 最近中文字幕免费在线观看| 欧美日本韩国一区二区三区视频| 国产精品久久久久久在线| 日韩一级欧美一级| 日韩一卡二卡在线| 国产一区二区日韩| 国产三区视频在线观看| 久久久久久97| 天天综合网天天| 亚洲精品欧美一区二区三区| 成人免费直播在线| 日韩精品久久久免费观看| 欧美激情黄色片| 国产成人在线小视频| 午夜亚洲性色福利视频| 中国黄色片免费看| 国产aⅴ精品一区二区三区色成熟| 日本黄色片在线播放| 中文字幕一区二区三区在线不卡| 久久成人在线观看| 91精品91久久久中77777| 精品国产亚洲av麻豆| 日韩成人av在线| 欧美激情二区| 国产91|九色| 欧美日本三级| 日日骚一区二区网站| 午夜欧美精品久久久久久久| 老司机午夜av| 成a人片国产精品| 欧美日韩国产一二三区| 亚洲成av人片观看| 一区二区日韩视频| 亚洲人成在线观看网站高清| 日本资源在线| 国产精品视频yy9099| 国产一区二区在线视频你懂的| 亚洲国产成人不卡| 妖精视频成人观看www| 999热精品视频| 欧美激情综合在线| 久草精品视频在线观看| 欧美精品亚洲二区| 国产美女视频一区二区三区| 久久久亚洲精品视频| 四虎精品一区二区免费| 久久一区二区精品| 国产精品国码视频| 777一区二区| 久久影院午夜论| 精品无码黑人又粗又大又长| 欧美日本免费一区二区三区| 精品亚洲综合| 欧美亚州一区二区三区| youjizz亚洲| 欧美日韩在线免费观看视频| 久久综合五月| 成人免费网站黄| 欧美日韩视频免费播放| 亚洲精品久久久蜜桃动漫 | 精品人伦一区二区| 欧美日韩午夜剧场| 人人妻人人澡人人爽人人欧美一区| 久久在线免费观看视频| 欧美大陆国产| 亚洲高清乱码| 欧美96一区二区免费视频| 中文字幕国产综合| 色综合久久综合网97色综合| 欧美特黄一级视频| 久久久久成人网| 在线视频亚洲欧美中文| 国产精品三级一区二区| 国产精品亚洲第一| 精品欧美一区二区久久久久| 制服丝袜亚洲精品中文字幕| 午夜激情在线观看| 成人羞羞国产免费| 911精品美国片911久久久| 日本精品一区在线| 综合av第一页| 99久久国产热无码精品免费| 久久伊人精品天天| 欧美不卡在线观看| 狠狠噜天天噜日日噜| www.在线成人| 成人精品在线看| 日韩国产欧美精品一区二区三区| 特黄毛片在线观看| 欧美精品七区| 蜜桃传媒麻豆第一区在线观看| 日韩欧美视频免费观看| 7777精品伊人久久久大香线蕉的| 国产色在线观看| 国产精品免费一区二区三区在线观看 | 国产一级精品毛片| 久久久精品一区二区| 欧美第一在线视频| 人妻夜夜添夜夜无码av| 久久精品人人| 欧美性受xxxx黑人| 欧美久久免费观看| 色呦呦久久久| 精品无人乱码一区二区三区的优势| 亚洲欧美日韩精品一区二区| 成人在线一级片| 91.com在线观看| 搞黄网站在线看| 免费亚洲精品视频| 免费在线观看视频一区| 亚洲天堂一级片| 亚洲国产天堂久久综合| 日本精品裸体写真集在线观看| 艳母动漫在线观看| zzijzzij亚洲日本少妇熟睡| 久久久久久亚洲av无码专区| 久久精品国产电影| 久久99精品国产自在现线| 日韩福利视频在线| 亚洲精品国久久99热| 全部免费毛片在线播放网站| 国产精品香蕉av| 欧美日韩三区| 影音先锋制服丝袜| 欧美刺激午夜性久久久久久久| 亚洲黄色免费看| 裸体大乳女做爰69| 久久蜜桃av一区二区天堂| 国产伦精品一区二区三区免.费 | 宅男在线精品国产免费观看| 国产电影一区二区三区| 久久久久99精品成人片我成大片| 精品少妇一区二区三区| 夜鲁夜鲁夜鲁视频在线播放| 国产精品美女在线播放| 91丝袜美腿高跟国产极品老师 | 免费在线精品视频|