亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

談談java的concurrent用法

2019-11-26 14:55:05
字體:
來源:轉載
供稿:網友

我們都知道,在JDK1.5之前,Java中要進行業務并發時,通常需要有程序員獨立完成代碼實現,當然也有一些開源的框架提供了這些功能,但是這些依然沒有JDK自帶的功能使用起來方便。而當針對高質量Java多線程并發程序設計時,為防止死蹦等現象的出現,比如使用java之前的wait()、notify()和synchronized等,每每需要考慮性能、死鎖、公平性、資源管理以及如何避免線程安全性方面帶來的危害等諸多因素,往往會采用一些較為復雜的安全策略,加重了程序員的開發負擔.萬幸的是,在JDK1.5出現之后,Sun大神(Doug Lea)終于為我們這些可憐的小程序員推出了java.util.concurrent工具包以簡化并發完成。開發者們借助于此,將有效的減少競爭條件(race conditions)和死鎖線程。concurrent包很好的解決了這些問題,為我們提供了更實用的并發程序模型。

Executor                  :具體Runnable任務的執行者。
ExecutorService           :一個線程池管理者,其實現類有多種,我會介紹一部分。我們能把Runnable,Callable提交到池中讓其調度。
Semaphore                 :一個計數信號量
ReentrantLock             :一個可重入的互斥鎖定 Lock,功能類似synchronized,但要強大的多。
Future                    :是與Runnable,Callable進行交互的接口,比如一個線程執行結束后取返回的結果等等,還提供了cancel終止線程。
BlockingQueue             :阻塞隊列。
CompletionService         : ExecutorService的擴展,可以獲得線程執行結果的
CountDownLatch            :一個同步輔助類,在完成一組正在其他線程中執行的操作之前,它允許一個或多個線程一直等待。
CyclicBarrier             :一個同步輔助類,它允許一組線程互相等待,直到到達某個公共屏障點
Future                    :Future 表示異步計算的結果。
ScheduledExecutorService :一個 ExecutorService,可安排在給定的延遲后運行或定期執行的命令。

接下來逐一介紹

Executors主要方法說明

newFixedThreadPool(固定大小線程池)

創建一個可重用固定線程集合的線程池,以共享的無界隊列方式來運行這些線程(只有要請求的過來,就會在一個隊列里等待執行)。如果在關閉前的執行期間由于失敗而導致任何線程終止,那么一個新線程將代替它執行后續的任務(如果需要)。

newCachedThreadPool(無界線程池,可以進行自動線程回收)

創建一個可根據需要創建新線程的線程池,但是在以前構造的線程可用時將重用它們。對于執行很多短期異步任務的程序而言,這些線程池通??商岣叱绦蛐阅?。調用 execute 將重用以前構造的線程(如果線程可用)。如果現有線程沒有可用的,則創建一個新線程并添加到池中。終止并從緩存中移除那些已有 60 秒鐘未被使用的線程。因此,長時間保持空閑的線程池不會使用任何資源。注意,可以使用 ThreadPoolExecutor 構造方法創建具有類似屬性但細節不同(例如超時參數)的線程池。

newSingleThreadExecutor(單個后臺線程)

創建一個使用單個 worker 線程的 Executor,以無界隊列方式來運行該線程。(注意,如果因為在關閉前的執行期間出現失敗而終止了此單個線程,那么如果需要,一個新線程將代替它執行后續的任務)??杀WC順序地執行各個任務,并且在任意給定的時間不會有多個線程是活動的。與其他等效的 newFixedThreadPool(1) 不同,可保證無需重新配置此方法所返回的執行程序即可使用其他的線程。

這些方法返回的都是ExecutorService對象,這個對象可以理解為就是一個線程池。

這個線程池的功能還是比較完善的??梢蕴峤蝗蝿誷ubmit()可以結束線程池shutdown()。

import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class MyExecutor extends Thread {private int index;public MyExecutor(int i){  this.index=i;}public void run(){  try{   System.out.println("["+this.index+"] start....");   Thread.sleep((int)(Math.random()*));   System.out.println("["+this.index+"] end.");  }  catch(Exception e){   e.printStackTrace();  }}public static void main(String args[]){  ExecutorService service=Executors.newFixedThreadPool();  for(int i=;i<;i++){   service.execute(new MyExecutor(i));   //service.submit(new MyExecutor(i));  }  System.out.println("submit finish");  service.shutdown();}}

雖然打印了一些信息,但是看的不是非常清晰,這個線程池是如何工作的,我們來將休眠的時間調長10倍。

Thread.sleep((int)(Math.random()*10000));

再來看,會清楚看到只能執行4個線程。當執行完一個線程后,才會又執行一個新的線程,也就是說,我們將所有的線程提交后,線程池會等待執行完最后shutdown。我們也會發現,提交的線程被放到一個“無界隊列里”。這是一個有序隊列(BlockingQueue,這個下面會說到)。

另外它使用了Executors的靜態函數生成一個固定的線程池,顧名思義,線程池的線程是不會釋放的,即使它是Idle。

這就會產生性能問題,比如如果線程池的大小為200,當全部使用完畢后,所有的線程會繼續留在池中,相應的內存和線程切換(while(true)+sleep循環)都會增加。

如果要避免這個問題,就必須直接使用ThreadPoolExecutor()來構造??梢韵裢ㄓ玫木€程池一樣設置“最大線程數”、“最小線程數”和“空閑線程keepAlive的時間”。

這個就是線程池基本用法。

Semaphore

一個計數信號量。從概念上講,信號量維護了一個許可集合。如有必要,在許可可用前會阻塞每一個 acquire(),然后再獲取該許可。每個 release() 添加一個許可,從而可能釋放一個正在阻塞的獲取者。但是,不使用實際的許可對象,Semaphore 只對可用許可的號碼進行計數,并采取相應的行動。

Semaphore 通常用于限制可以訪問某些資源(物理或邏輯的)的線程數目。例如,下面的類使用信號量控制對內容池的訪問:

這里是一個實際的情況,大家排隊上廁所,廁所只有兩個位置,來了10個人需要排隊。

import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;public class MySemaphore extends Thread {Semaphore position;private int id;public MySemaphore(int i,Semaphore s){  this.id=i;  this.position=s;}public void run(){  try{   if(position.availablePermits()>){   System.out.println("顧客["+this.id+"]進入廁所,有空位");   }   else{   System.out.println("顧客["+this.id+"]進入廁所,沒空位,排隊");   }   position.acquire();   System.out.println("顧客["+this.id+"]獲得坑位");   Thread.sleep((int)(Math.random()*));   System.out.println("顧客["+this.id+"]使用完畢");   position.release();  }  catch(Exception e){   e.printStackTrace();  }}public static void main(String args[]){  ExecutorService list=Executors.newCachedThreadPool();  Semaphore position=new Semaphore();  for(int i=;i<;i++){   list.submit(new MySemaphore(i+,position));  }  list.shutdown();  position.acquireUninterruptibly();  System.out.println("使用完畢,需要清掃了");  position.release();}}

ReentrantLock

一個可重入的互斥鎖定 Lock,它具有與使用 synchronized 方法和語句所訪問的隱式監視器鎖定相同的一些基本行為和語義,但功能更強大。

ReentrantLock 將由最近成功獲得鎖定,并且還沒有釋放該鎖定的線程所擁有。當鎖定沒有被另一個線程所擁有時,調用 lock 的線程將成功獲取該鎖定并返回。如果當前線程已經擁有該鎖定,此方法將立即返回??梢允褂?isHeldByCurrentThread() 和 getHoldCount() 方法來檢查此情況是否發生。

此類的構造方法接受一個可選的公平參數。

當設置為 true時,在多個線程的爭用下,這些鎖定傾向于將訪問權授予等待時間最長的線程。否則此鎖定將無法保證任何特定訪問順序。

與采用默認設置(使用不公平鎖定)相比,使用公平鎖定的程序在許多線程訪問時表現為很低的總體吞吐量(即速度很慢,常常極其慢),但是在獲得鎖定和保證鎖定分配的均衡性時差異較小。

不過要注意的是,公平鎖定不能保證線程調度的公平性。因此,使用公平鎖定的眾多線程中的一員可能獲得多倍的成功機會,這種情況發生在其他活動線程沒有被處理并且目前并未持有鎖定時。
還要注意的是,未定時的 tryLock 方法并沒有使用公平設置。因為即使其他線程正在等待,只要該鎖定是可用的,此方法就可以獲得成功。

建議總是 立即實踐,使用 try 塊來調用 lock,在之前/之后的構造中,最典型的代碼如下:

class X {  private final ReentrantLock lock = new ReentrantLock();  // ...  public void m() {   lock.lock(); // block until condition holds   try {    // ... method body   } finally {    lock.unlock()   }  }}

我的例子:

import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.locks.ReentrantLock;public class MyReentrantLock extends Thread{TestReentrantLock lock;private int id;public MyReentrantLock(int i,TestReentrantLock test){  this.id=i;  this.lock=test;}public void run(){  lock.print(id);}public static void main(String args[]){  ExecutorService service=Executors.newCachedThreadPool();  TestReentrantLock lock=new TestReentrantLock();  for(int i=;i<;i++){   service.submit(new MyReentrantLock(i,lock));  }  service.shutdown();}}class TestReentrantLock{private ReentrantLock lock=new ReentrantLock();public void print(int str){  try{   lock.lock();   System.out.println(str+"獲得");   Thread.sleep((int)(Math.random()*));  }  catch(Exception e){   e.printStackTrace();  }  finally{   System.out.println(str+"釋放");   lock.unlock();  }}}

BlockingQueue

支持兩個附加操作的 Queue,這兩個操作是:檢索元素時等待隊列變為非空,以及存儲元素時等待空間變得可用。

BlockingQueue 不接受 null 元素。試圖 add、put 或 offer 一個 null 元素時,某些實現會拋出 NullPointerException。null 被用作指示 poll 操作失敗的警戒值。

BlockingQueue 可以是限定容量的。它在任意給定時間都可以有一個 remainingCapacity,超出此容量,便無法無阻塞地 put 額外的元素。

沒有任何內部容量約束的 BlockingQueue 總是報告 Integer.MAX_VALUE 的剩余容量。

BlockingQueue 實現主要用于生產者-使用者隊列,但它另外還支持 Collection 接口。因此,舉例來說,使用 remove(x) 從隊列中移除任意一個元素是有可能的。

然而,這種操作通常不 會有效執行,只能有計劃地偶爾使用,比如在取消排隊信息時。

BlockingQueue 實現是線程安全的。所有排隊方法都可以使用內部鎖定或其他形式的并發控制來自動達到它們的目的。

然而,大量的 Collection 操作(addAll、containsAll、retainAll 和 removeAll)沒有 必要自動執行,除非在實現中特別說明。

因此,舉例來說,在只添加了 c 中的一些元素后,addAll(c) 有可能失敗(拋出一個異常)。

BlockingQueue 實質上不 支持使用任何一種“close”或“shutdown”操作來指示不再添加任何項。

這種功能的需求和使用有依賴于實現的傾向。例如,一種常用的策略是:對于生產者,插入特殊的 end-of-stream 或 poison 對象,并根據使用者獲取這些對象的時間來對它們進行解釋。

下面的例子演示了這個阻塞隊列的基本功能。

import java.util.concurrent.BlockingQueue;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.LinkedBlockingQueue;public class MyBlockingQueue extends Thread {public static BlockingQueue<String> queue = new LinkedBlockingQueue<String>();private int index;public MyBlockingQueue(int i) {  this.index = i;}public void run() {  try {  queue.put(String.valueOf(this.index));  System.out.println("{" + this.index + "} in queue!");  } catch (Exception e) {  e.printStackTrace();  }}public static void main(String args[]) {  ExecutorService service = Executors.newCachedThreadPool();  for (int i = ; i < ; i++) {  service.submit(new MyBlockingQueue(i));  }  Thread thread = new Thread() {  public void run() {   try {   while (true) {    Thread.sleep((int) (Math.random() * ));    if(MyBlockingQueue.queue.isEmpty())    break;    String str = MyBlockingQueue.queue.take();    System.out.println(str + " has take!");   }   } catch (Exception e) {   e.printStackTrace();   }  }  };  service.submit(thread);  service.shutdown();}}

---------------------執行結果-----------------
{0} in queue!
{1} in queue!
{2} in queue!
{3} in queue!
0 has take!
{4} in queue!
1 has take!
{6} in queue!
2 has take!
{7} in queue!
3 has take!
{8} in queue!
4 has take!
{5} in queue!
6 has take!
{9} in queue!
7 has take!
8 has take!
5 has take!
9 has take!
-----------------------------------------

CompletionService

將生產新的異步任務與使用已完成任務的結果分離開來的服務。生產者 submit 執行的任務。使用者 take 已完成的任務,并按照完成這些任務的順序處理它們的結果。例如,CompletionService 可以用來管理異步 IO ,執行讀操作的任務作為程序或系統的一部分提交,然后,當完成讀操作時,會在程序的不同部分執行其他操作,執行操作的順序可能與所請求的順序不同。

通常,CompletionService 依賴于一個單獨的 Executor 來實際執行任務,在這種情況下,CompletionService 只管理一個內部完成隊列。ExecutorCompletionService 類提供了此方法的一個實現。

import java.util.concurrent.Callable;import java.util.concurrent.CompletionService;import java.util.concurrent.ExecutorCompletionService;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class MyCompletionService implements Callable<String> {private int id;public MyCompletionService(int i){  this.id=i;}public static void main(String[] args) throws Exception{  ExecutorService service=Executors.newCachedThreadPool();  CompletionService<String> completion=new ExecutorCompletionService<String>(service);  for(int i=;i<;i++){  completion.submit(new MyCompletionService(i));  }  for(int i=;i<;i++){  System.out.println(completion.take().get());  }  service.shutdown();}public String call() throws Exception {  Integer time=(int)(Math.random()*);  try{  System.out.println(this.id+" start");  Thread.sleep(time);  System.out.println(this.id+" end");  }  catch(Exception e){  e.printStackTrace();  }  return this.id+":"+time;}}

CountDownLatch

一個同步輔助類,在完成一組正在其他線程中執行的操作之前,它允許一個或多個線程一直等待。

用給定的計數 初始化 CountDownLatch。由于調用了 countDown() 方法,所以在當前計數到達零之前,await 方法會一直受阻塞。

之后,會釋放所有等待的線程,await 的所有后續調用都將立即返回。這種現象只出現一次――計數無法被重置。如果需要重置計數,請考慮使用 CyclicBarrier。

CountDownLatch 是一個通用同步工具,它有很多用途。將計數 1 初始化的 CountDownLatch 用作一個簡單的開/關鎖存器,或入口:在通過調用 countDown() 的線程打開入口前,所有調用 await 的線程都一直在入口處等待。

用 N 初始化的 CountDownLatch 可以使一個線程在 N 個線程完成某項操作之前一直等待,或者使其在某項操作完成 N 次之前一直等待。

CountDownLatch 的一個有用特性是,它不要求調用 countDown 方法的線程等到計數到達零時才繼續,而在所有線程都能通過之前,它只是阻止任何線程繼續通過一個 await。

一下的例子是別人寫的,非常形象。

import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class TestCountDownLatch {public static void main(String[] args) throws InterruptedException {  // 開始的倒數鎖  final CountDownLatch begin = new CountDownLatch();  // 結束的倒數鎖  final CountDownLatch end = new CountDownLatch();  // 十名選手  final ExecutorService exec = Executors.newFixedThreadPool();  for (int index = ; index < ; index++) {  final int NO = index + ;  Runnable run = new Runnable() {   public void run() {   try {    begin.await();//一直阻塞    Thread.sleep((long) (Math.random() * ));    System.out.println("No." + NO + " arrived");   } catch (InterruptedException e) {   } finally {    end.countDown();   }   }  };  exec.submit(run);  }  System.out.println("Game Start");  begin.countDown();  end.await();  System.out.println("Game Over");  exec.shutdown();}}

CountDownLatch最重要的方法是countDown()和await(),前者主要是倒數一次,后者是等待倒數到0,如果沒有到達0,就只有阻塞等待了。

CyclicBarrier

一個同步輔助類,它允許一組線程互相等待,直到到達某個公共屏障點 (common barrier point)。

在涉及一組固定大小的線程的程序中,這些線程必須不時地互相等待,此時 CyclicBarrier 很有用。因為該 barrier 在釋放等待線程后可以重用,所以稱它為循環 的 barrier。

CyclicBarrier 支持一個可選的 Runnable 命令,在一組線程中的最后一個線程到達之后(但在釋放所有線程之前),該命令只在每個屏障點運行一次。若在繼續所有參與線程之前更新共享狀態,此屏障操作 很有用。

示例用法:下面是一個在并行分解設計中使用 barrier 的例子,很經典的旅行團例子:

import java.text.SimpleDateFormat;import java.util.Date;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class TestCyclicBarrier { // 徒步需要的時間: Shenzhen, Guangzhou, Shaoguan, Changsha, Wuhan private static int[] timeWalk = { , , , , }; // 自駕游 private static int[] timeSelf = { , , , , }; // 旅游大巴 private static int[] timeBus = { , , , , }; static String now() {   SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");   return sdf.format(new Date()) + ": "; } static class Tour implements Runnable {   private int[] times;   private CyclicBarrier barrier;   private String tourName;   public Tour(CyclicBarrier barrier, String tourName, int[] times) {    this.times = times;    this.tourName = tourName;    this.barrier = barrier;   }   public void run() {    try {     Thread.sleep(times[] * );     System.out.println(now() + tourName + " Reached Shenzhen");     barrier.await();     Thread.sleep(times[] * );     System.out.println(now() + tourName + " Reached Guangzhou");     barrier.await();     Thread.sleep(times[] * );     System.out.println(now() + tourName + " Reached Shaoguan");     barrier.await();     Thread.sleep(times[] * );     System.out.println(now() + tourName + " Reached Changsha");     barrier.await();     Thread.sleep(times[] * );     System.out.println(now() + tourName + " Reached Wuhan");     barrier.await();    } catch (InterruptedException e) {    } catch (BrokenBarrierException e) {    }   } } public static void main(String[] args) {   // 三個旅行團   CyclicBarrier barrier = new CyclicBarrier();   ExecutorService exec = Executors.newFixedThreadPool();   exec.submit(new Tour(barrier, "WalkTour", timeWalk));   exec.submit(new Tour(barrier, "SelfTour", timeSelf));//當我們把下面的這段代碼注釋后,會發現,程序阻塞了,無法繼續運行下去。   exec.submit(new Tour(barrier, "BusTour", timeBus));   exec.shutdown(); }}

CyclicBarrier最重要的屬性就是參與者個數,另外最要方法是await()。當所有線程都調用了await()后,就表示這些線程都可以繼續執行,否則就會等待。

Future

Future 表示異步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,并檢索計算的結果。

計算完成后只能使用 get 方法來檢索結果,如有必要,計算完成前可以阻塞此方法。取消則由 cancel 方法來執行。

還提供了其他方法,以確定任務是正常完成還是被取消了。一旦計算完成,就不能再取消計算。

如果為了可取消性而使用 Future但又不提供可用的結果,則可以聲明 Future<?> 形式類型、并返回 null 作為基礎任務的結果。

這個我們在前面CompletionService已經看到了,這個Future的功能,而且這個可以在提交線程的時候被指定為一個返回對象的。

ScheduledExecutorService

一個 ExecutorService,可安排在給定的延遲后運行或定期執行的命令。

schedule 方法使用各種延遲創建任務,并返回一個可用于取消或檢查執行的任務對象。scheduleAtFixedRate 和 scheduleWithFixedDelay 方法創建并執行某些在取消前一直定期運行的任務。

用 Executor.execute(java.lang.Runnable) 和 ExecutorService 的 submit 方法所提交的命令,通過所請求的 0 延遲進行安排。

schedule 方法中允許出現 0 和負數延遲(但不是周期),并將這些視為一種立即執行的請求。

所有的 schedule 方法都接受相對 延遲和周期作為參數,而不是絕對的時間或日期。將以 Date 所表示的絕對時間轉換成要求的形式很容易。

例如,要安排在某個以后的日期運行,可以使用:schedule(task, date.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS)。

但是要注意,由于網絡時間同步協議、時鐘漂移或其他因素的存在,因此相對延遲的期滿日期不必與啟用任務的當前 Date 相符。

Executors 類為此包中所提供的 ScheduledExecutorService 實現提供了便捷的工廠方法。

一下的例子也是網上比較流行的。

import static java.util.concurrent.TimeUnit.SECONDS;import java.util.Date;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.ScheduledFuture;public class TestScheduledThread {public static void main(String[] args) {  final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool();  final Runnable beeper = new Runnable() {  int count = ;  public void run() {   System.out.println(new Date() + " beep " + (++count));  }  };  // 秒鐘后運行,并每隔秒運行一次  final ScheduledFuture beeperHandle = scheduler.scheduleAtFixedRate(beeper, , , SECONDS);  // 秒鐘后運行,并每次在上次任務運行完后等待秒后重新運行  final ScheduledFuture beeperHandle = scheduler.scheduleWithFixedDelay(beeper, , , SECONDS);  // 秒后結束關閉任務,并且關閉Scheduler  scheduler.schedule(new Runnable() {  public void run() {   beeperHandle.cancel(true);   beeperHandle.cancel(true);   scheduler.shutdown();  }  }, , SECONDS);}}

這樣我們就把concurrent包下比較重要的功能都已經總結完了,希望對我們理解能有幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩大片免费观看视频播放| 国产成人自拍视频在线观看| 成人精品一区二区三区| 亚洲人成欧美中文字幕| 91亚洲一区精品| 欧美激情第一页xxx| 久久久久国产精品免费| 国产精品精品久久久| 亚洲美女精品成人在线视频| 欧美在线视频观看免费网站| 国产欧美久久久久久| 精品亚洲一区二区三区四区五区| 欧美日韩在线观看视频小说| 91久久嫩草影院一区二区| 国产成人亚洲综合91精品| 97激碰免费视频| 精品性高朝久久久久久久| 亚洲国产精品一区二区久| 久久久亚洲精品视频| 久久久久日韩精品久久久男男| 国产在线精品自拍| 亚洲午夜性刺激影院| 日韩欧美在线播放| 久久久av亚洲男天堂| 色综合久综合久久综合久鬼88| 91精品久久久久久久久久另类| 久久99精品视频一区97| 久久久视频精品| 九九热这里只有在线精品视| 国产一区二区在线播放| 欧美精品激情在线观看| 国产视频精品va久久久久久| 欧美在线亚洲在线| 一区二区三区国产视频| 日韩动漫免费观看电视剧高清| 亚洲一区二区三区久久| 日韩电视剧免费观看网站| 久久久久久97| 成人中心免费视频| 日韩高清免费在线| 国产精品久久久一区| 欧美日韩国产麻豆| 久久99热精品| 青青草99啪国产免费| 久久精品久久精品亚洲人| 亚洲欧美成人在线| 国产精品www色诱视频| 日韩午夜在线视频| 精品色蜜蜜精品视频在线观看| 久久久久久久999精品视频| 日韩一区二区精品视频| 欧美电影电视剧在线观看| 久久夜精品va视频免费观看| 亚洲国产天堂久久国产91| 5566日本婷婷色中文字幕97| 国产精品三级网站| 欧美激情第6页| 91精品久久久久久久久久久久久| 日韩精品欧美国产精品忘忧草| 欧美性猛交xxx| 国产精品96久久久久久又黄又硬| 久久久999国产精品| 在线亚洲国产精品网| 国产一区私人高清影院| 欧美另类极品videosbest最新版本| 久久精品亚洲国产| 久久九九热免费视频| 原创国产精品91| 欧美俄罗斯性视频| 中文字幕亚洲一区二区三区五十路| 国产精品视频精品视频| 亚洲乱码av中文一区二区| 亚洲国产婷婷香蕉久久久久久| 亚洲专区在线视频| 成人免费观看a| 久久亚洲影音av资源网| 亚洲午夜久久久影院| 日韩电影免费观看在线| 欧美一级视频免费在线观看| www.xxxx欧美| 欧美日韩一区二区三区在线免费观看| 亚洲精品97久久| 在线丨暗呦小u女国产精品| 久久精品免费播放| 国产拍精品一二三| 久久免费少妇高潮久久精品99| 久久精品视频一| 欧美日韩在线看| 国产精品三级美女白浆呻吟| 精品视频—区二区三区免费| 欧美巨乳在线观看| 国产精品91免费在线| 精品一区二区三区电影| 91精品在线国产| 亚洲男人av电影| 欧美另类第一页| 在线播放日韩专区| 日韩av片电影专区| 成人网中文字幕| 国产精品美女主播在线观看纯欲| 欧美国产高跟鞋裸体秀xxxhd| 色综合久综合久久综合久鬼88| 国产在线观看91精品一区| 精品久久久久久久中文字幕| 久久久久久伊人| 亚洲精品视频网上网址在线观看| 日韩中文字幕视频在线观看| 成人做爰www免费看视频网站| 97在线观看视频国产| 久久视频在线观看免费| 精品爽片免费看久久| 国产精品一区二区三区毛片淫片| 久久777国产线看观看精品| 日韩av中文字幕在线免费观看| 国产精品扒开腿爽爽爽视频| www国产精品com| 欧美精品一本久久男人的天堂| 国产精品日韩在线播放| 精品国产欧美成人夜夜嗨| 亚洲精品久久久久久久久久久久| 久久这里有精品| 国产精品视频白浆免费视频| 亚洲美女又黄又爽在线观看| 日韩经典一区二区三区| 亚洲男人的天堂在线| 在线免费看av不卡| 浅井舞香一区二区| 欧美激情综合亚洲一二区| 91在线|亚洲| 日av在线播放中文不卡| 97视频在线观看视频免费视频| 日韩激情在线视频| 精品一区二区三区三区| 久久久久一本一区二区青青蜜月| 性欧美视频videos6一9| 欧美日韩国产限制| 日韩免费在线播放| 久久亚洲精品一区| 欧美中文字幕在线播放| 一区二区三区动漫| 久久成人综合视频| 在线精品高清中文字幕| 中文字幕综合在线| 欧美大尺度电影在线观看| 亚洲经典中文字幕| 91chinesevideo永久地址| 亚洲人免费视频| 午夜精品久久久久久久男人的天堂| 欧美韩日一区二区| 亚洲国产一区二区三区在线观看| 欧美激情精品久久久久久变态| 亚洲最新在线视频| 黑人欧美xxxx| 亚洲xxxxx| 日韩亚洲成人av在线| 中文字幕av日韩| 久久不射电影网| 2018中文字幕一区二区三区| 成人国产在线视频| 国产97人人超碰caoprom| 国产ts一区二区| 亚洲日本成人女熟在线观看| 中文字幕综合在线| 亚州精品天堂中文字幕|