一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語言 - JAVA教程 - 深入解析Java并發(fā)程序中線程的同步與線程鎖的使用

深入解析Java并發(fā)程序中線程的同步與線程鎖的使用

2020-04-07 11:41chenssy JAVA教程

這篇文章主要介紹了深入解析Java并發(fā)編程中線程的同步與線程鎖的使用,synchronized和lock是Java中最常見的控制線程的方法,需要的朋友可以參考下

synchronized關(guān)鍵字

synchronized,我們謂之鎖,主要用來給方法、代碼塊加鎖。當(dāng)某個(gè)方法或者代碼塊使用synchronized時(shí),那么在同一時(shí)刻至多僅有有一個(gè)線程在執(zhí)行該段代碼。當(dāng)有多個(gè)線程訪問同一對(duì)象的加鎖方法/代碼塊時(shí),同一時(shí)間只有一個(gè)線程在執(zhí)行,其余線程必須要等待當(dāng)前線程執(zhí)行完之后才能執(zhí)行該代碼段。但是,其余線程是可以訪問該對(duì)象中的非加鎖代碼塊的。

synchronized主要包括兩種方法:synchronized 方法、synchronized 塊。

synchronized 方法

通過在方法聲明中加入 synchronized關(guān)鍵字來聲明 synchronized 方法。如:

public synchronized void getResult(); 
synchronized方法控制對(duì)類成員變量的訪問。它是如何來避免類成員變量的訪問控制呢?我們知道方法使用了synchronized關(guān)鍵字表明該方法已加鎖,在任一線程在訪問改方法時(shí)都必須要判斷該方法是否有其他線程在“獨(dú)占”。每個(gè)類實(shí)例對(duì)應(yīng)一個(gè)把鎖,每個(gè)synchronized方法都必須調(diào)用該方法的類實(shí)例的鎖方能執(zhí)行,否則所屬線程阻塞,方法一旦執(zhí)行,就獨(dú)占該鎖,直到從該方法返回時(shí)才將鎖釋放,被阻塞的線程方能獲得該鎖。

其實(shí)synchronized方法是存在缺陷的,如果我們將一個(gè)很大的方法聲明為synchronized將會(huì)大大影響效率的。如果多個(gè)線程在訪問一個(gè)synchronized方法,那么同一時(shí)刻只有一個(gè)線程在執(zhí)行該方法,而其他線程都必須等待,但是如果該方法沒有使用synchronized,則所有線程可以在同一時(shí)刻執(zhí)行它,減少了執(zhí)行的總時(shí)間。所以如果我們知道一個(gè)方法不會(huì)被多個(gè)線程執(zhí)行到或者說不存在資源共享的問題,則不需要使用synchronized關(guān)鍵字。但是如果一定要使用synchronized關(guān)鍵字,那么我們可以synchronized代碼塊來替換synchronized方法。

synchronized 塊

synchronized代碼塊所起到的作用和synchronized方法一樣,只不過它使臨界區(qū)變的盡可能短了,換句話說:它只把需要的共享數(shù)據(jù)保護(hù)起來,其余的長(zhǎng)代碼塊留出此操作。語法如下:

?
1
2
3
4
5
6
7
8
synchronized(object) {
 //允許訪問控制的代碼
}
如果我們需要以這種方式來使用synchronized關(guān)鍵字,那么必須要通過一個(gè)對(duì)象引用來作為參數(shù),通常這個(gè)參數(shù)我們常使用為this.
 
synchronized (this) {
 //允許訪問控制的代碼
}

對(duì)于synchronized(this)有如下理解:

1、當(dāng)兩個(gè)并發(fā)線程訪問同一個(gè)對(duì)象object中的這個(gè)synchronized(this)同步代碼塊時(shí),一個(gè)時(shí)間內(nèi)只能有一個(gè)線程得到執(zhí)行。另一個(gè)線程必須等待當(dāng)前線程執(zhí)行完這個(gè)代碼塊以后才能執(zhí)行該代碼塊。

2、然而,當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)同步代碼塊時(shí),另一個(gè)線程仍然可以訪問object中的非synchronized(this)同步代碼塊。

3、尤其關(guān)鍵的是,當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)同步代碼塊時(shí),其他線程對(duì)object中所有其他synchronized(this)同步代碼塊得訪問將被阻塞。

4、第三個(gè)例子同樣適用其他同步代碼塊。也就是說,當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)同步代碼塊時(shí),它就獲得了這個(gè)object的對(duì)象鎖。結(jié)果,其他線程對(duì)該object對(duì)象所有同步代碼部分的訪問都將被暫時(shí)阻塞。


在java多線程中存在一個(gè)“先來后到”的原則,也就是說誰先搶到鑰匙,誰先用。我們知道為避免資源競(jìng)爭(zhēng)產(chǎn)生問題,java使用同步機(jī)制來避免,而同步機(jī)制是使用鎖概念來控制的。那么在Java程序當(dāng)中,鎖是如何體現(xiàn)的呢?這里我們需要弄清楚兩個(gè)概念:

什么是鎖?在日常生活中,它就是一個(gè)加在門、箱子、抽屜等物體上的封緘器,防止別人偷窺或者偷盜,起到一個(gè)保護(hù)的作用。在java中同樣如此,鎖對(duì)對(duì)象起到一個(gè)保護(hù)的作用,一個(gè)線程如果獨(dú)占了某個(gè)資源,那么其他的線程別想用,想用?等我用完再說吧!

在java程序運(yùn)行環(huán)境中,JVM需要對(duì)兩類線程共享的數(shù)據(jù)進(jìn)行協(xié)調(diào):

1、保存在堆中的實(shí)例變量

2、保存在方法區(qū)中的類變量。

在java虛擬機(jī)中,每個(gè)對(duì)象和類在邏輯上都是和一個(gè)監(jiān)視器相關(guān)聯(lián)的。對(duì)于對(duì)象來說,相關(guān)聯(lián)的監(jiān)視器保護(hù)對(duì)象的實(shí)例變量。 對(duì)于類來說,監(jiān)視器保護(hù)類的類變量。如果一個(gè)對(duì)象沒有實(shí)例變量,或者說一個(gè)類沒有變量,相關(guān)聯(lián)的監(jiān)視器就什么也不監(jiān)視。

為了實(shí)現(xiàn)監(jiān)視器的排他性監(jiān)視能力,java虛擬機(jī)為每一個(gè)對(duì)象和類都關(guān)聯(lián)一個(gè)鎖。代表任何時(shí)候只允許一個(gè)線程擁有的特權(quán)。線程訪問實(shí)例變量或者類變量不需鎖。 如果某個(gè)線程獲取了鎖,那么在它釋放該鎖之前其他線程是不可能獲取同樣鎖的。一個(gè)線程可以多次對(duì)同一個(gè)對(duì)象上鎖。對(duì)于每一個(gè)對(duì)象,java虛擬機(jī)維護(hù)一個(gè)加鎖計(jì)數(shù)器,線程每獲得一次該對(duì)象,計(jì)數(shù)器就加1,每釋放一次,計(jì)數(shù)器就減 1,當(dāng)計(jì)數(shù)器值為0時(shí),鎖就被完全釋放了。
java編程人員不需要自己動(dòng)手加鎖,對(duì)象鎖是java虛擬機(jī)內(nèi)部使用的。在java程序中,只需要使用synchronized塊或者synchronized方法就可以標(biāo)志一個(gè)監(jiān)視區(qū)域。當(dāng)每次進(jìn)入一個(gè)監(jiān)視區(qū)域時(shí),java 虛擬機(jī)都會(huì)自動(dòng)鎖上對(duì)象或者類。

一個(gè)簡(jiǎn)單的鎖

在使用synchronized時(shí),我們是這樣使用鎖的:

?
1
2
3
4
5
6
7
public class ThreadTest {
 public void test(){
  synchronized(this){
   //do something
  }
 }
}

synchronized可以確保在同一時(shí)間內(nèi)只有一個(gè)線程在執(zhí)行dosomething。下面是使用lock替代synchronized:

?
1
2
3
4
5
6
7
8
public class ThreadTest {
 Lock lock = new Lock();
 public void test(){
  lock.lock();
  //do something
  lock.unlock();
 }
}

lock()方法會(huì)對(duì)Lock實(shí)例對(duì)象進(jìn)行加鎖,因此所有對(duì)該對(duì)象調(diào)用lock()方法的線程都會(huì)被阻塞,直到該Lock對(duì)象的unlock()方法被調(diào)用。


鎖的是什么?

在這個(gè)問題之前我們必須要明確一點(diǎn):無論synchronized關(guān)鍵字加在方法上還是對(duì)象上,它取得的鎖都是對(duì)象。在java中每一個(gè)對(duì)象都可以作為鎖,它主要體現(xiàn)在下面三個(gè)方面:

對(duì)于同步方法,鎖是當(dāng)前實(shí)例對(duì)象。
對(duì)于同步方法塊,鎖是Synchonized括號(hào)里配置的對(duì)象。


對(duì)于靜態(tài)同步方法,鎖是當(dāng)前對(duì)象的Class對(duì)象。
首先我們先看下面例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ThreadTest_01 implements Runnable{
 
 @Override
 public synchronized void run() {
  for(int i = 0 ; i < 3 ; i++){
   System.out.println(Thread.currentThread().getName() + "run......");
  }
 }
  
 public static void main(String[] args) {
  for(int i = 0 ; i < 5 ; i++){
   new Thread(new ThreadTest_01(),"Thread_" + i).start();
  }
 }
}

部分運(yùn)行結(jié)果:

?
1
2
3
4
5
6
7
8
9
Thread_2run......
Thread_2run......
Thread_4run......
Thread_4run......
Thread_3run......
Thread_3run......
Thread_3run......
Thread_2run......
Thread_4run......

這個(gè)結(jié)果與我們預(yù)期的結(jié)果有點(diǎn)不同(這些線程在這里亂跑),照理來說,run方法加上synchronized關(guān)鍵字后,會(huì)產(chǎn)生同步效果,這些線程應(yīng)該是一個(gè)接著一個(gè)執(zhí)行run方法的。在上面LZ提到,一個(gè)成員方法加上synchronized關(guān)鍵字后,實(shí)際上就是給這個(gè)成員方法加上鎖,具體點(diǎn)就是以這個(gè)成員方法所在的對(duì)象本身作為對(duì)象鎖。但是在這個(gè)實(shí)例當(dāng)中我們一共new了10個(gè)ThreadTest對(duì)象,那個(gè)每個(gè)線程都會(huì)持有自己線程對(duì)象的對(duì)象鎖,這必定不能產(chǎn)生同步的效果。所以:如果要對(duì)這些線程進(jìn)行同步,那么這些線程所持有的對(duì)象鎖應(yīng)當(dāng)是共享且唯一的!

這個(gè)時(shí)候synchronized鎖住的是那個(gè)對(duì)象?它鎖住的就是調(diào)用這個(gè)同步方法對(duì)象。就是說threadTest這個(gè)對(duì)象在不同線程中執(zhí)行同步方法,就會(huì)形成互斥。達(dá)到同步的效果。所以將上面的new Thread(new ThreadTest_01(),”Thread_” + i).start(); 修改為new Thread(threadTest,”Thread_” + i).start();就可以了。

對(duì)于同步方法,鎖是當(dāng)前實(shí)例對(duì)象。

上面實(shí)例是使用synchronized方法,我們?cè)诳纯磗ynchronized代碼塊:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class ThreadTest_02 extends Thread{
 
 private String lock ;
 private String name;
  
 public ThreadTest_02(String name,String lock){
  this.name = name;
  this.lock = lock;
 }
  
 @Override
 public void run() {
  synchronized (lock) {
   for(int i = 0 ; i < 3 ; i++){
    System.out.println(name + " run......");
   }
  }
 }
  
 public static void main(String[] args) {
  String lock = new String("test");
  for(int i = 0 ; i < 5 ; i++){
   new ThreadTest_02("ThreadTest_" + i,lock).start();
  }
 }
}

運(yùn)行結(jié)果:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ThreadTest_0 run......
ThreadTest_0 run......
ThreadTest_0 run......
ThreadTest_1 run......
ThreadTest_1 run......
ThreadTest_1 run......
ThreadTest_4 run......
ThreadTest_4 run......
ThreadTest_4 run......
ThreadTest_3 run......
ThreadTest_3 run......
ThreadTest_3 run......
ThreadTest_2 run......
ThreadTest_2 run......
ThreadTest_2 run......

在main方法中我們創(chuàng)建了一個(gè)String對(duì)象lock,并將這個(gè)對(duì)象賦予每一個(gè)ThreadTest2線程對(duì)象的私有變量lock。我們知道java中存在一個(gè)字符串池,那么這些線程的lock私有變量實(shí)際上指向的是堆內(nèi)存中的同一個(gè)區(qū)域,即存放main函數(shù)中的lock變量的區(qū)域,所以對(duì)象鎖是唯一且共享的。線程同步!!

在這里synchronized鎖住的就是lock這個(gè)String對(duì)象。

  對(duì)于同步方法塊,鎖是Synchonized括號(hào)里配置的對(duì)象。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ThreadTest_03 extends Thread{
 
 public synchronized static void test(){
  for(int i = 0 ; i < 3 ; i++){
   System.out.println(Thread.currentThread().getName() + " run......");
  }
 }
  
 @Override
 public void run() {
  test();
 }
 
 public static void main(String[] args) {
  for(int i = 0 ; i < 5 ; i++){
   new ThreadTest_03().start();
  }
 }
}

運(yùn)行結(jié)果:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Thread-0 run......
Thread-0 run......
Thread-0 run......
Thread-4 run......
Thread-4 run......
Thread-4 run......
Thread-1 run......
Thread-1 run......
Thread-1 run......
Thread-2 run......
Thread-2 run......
Thread-2 run......
Thread-3 run......
Thread-3 run......
Thread-3 run......

在這個(gè)實(shí)例中,run方法使用的是一個(gè)同步方法,而且是static的同步方法,那么這里synchronized鎖的又是什么呢?我們知道static超脫于對(duì)象之外,它屬于類級(jí)別的。所以,對(duì)象鎖就是該靜態(tài)放發(fā)所在的類的Class實(shí)例。由于在JVM中,所有被加載的類都有唯一的類對(duì)象,在該實(shí)例當(dāng)中就是唯一的 ThreadTest_03.class對(duì)象。不管我們創(chuàng)建了該類的多少實(shí)例,但是它的類實(shí)例仍然是一個(gè)!所以對(duì)象鎖是唯一且共享的。線程同步!!

對(duì)于靜態(tài)同步方法,鎖是當(dāng)前對(duì)象的Class對(duì)象。

如果一個(gè)類中定義了一個(gè)synchronized的static函數(shù)A,也定義了一個(gè)synchronized的instance函數(shù)B,那么這個(gè)類的同一對(duì)象Obj,在多線程中分別訪問A和B兩個(gè)方法時(shí),不會(huì)構(gòu)成同步,因?yàn)樗鼈兊逆i都不一樣。A方法的鎖是Obj這個(gè)對(duì)象,而B的鎖是Obj所屬的那個(gè)Class。

鎖的升級(jí)

java中鎖一共有四種狀態(tài),無鎖狀態(tài),偏向鎖狀態(tài),輕量級(jí)鎖狀態(tài)和重量級(jí)鎖狀態(tài),它會(huì)隨著競(jìng)爭(zhēng)情況逐漸升級(jí)。鎖可以升級(jí)但不能降級(jí),意味著偏向鎖升級(jí)成輕量級(jí)鎖后不能降級(jí)成偏向鎖。這種鎖升級(jí)卻不能降級(jí)的策略,目的是為了提高獲得鎖和釋放鎖的效率。下面主要部分主要是對(duì)博客:聊聊并發(fā)(二)Java SE1.6中的Synchronized的總結(jié)。

鎖自旋

我們知道在當(dāng)某個(gè)線程在進(jìn)入同步方法/代碼塊時(shí)若發(fā)現(xiàn)該同步方法/代碼塊被其他現(xiàn)在所占,則它就要等待,進(jìn)入阻塞狀態(tài),這個(gè)過程性能是低下的。

在遇到鎖的爭(zhēng)用或許等待事,線程可以不那么著急進(jìn)入阻塞狀態(tài),而是等一等,看看鎖是不是馬上就釋放了,這就是鎖自旋。鎖自旋在一定程度上可以對(duì)線程進(jìn)行優(yōu)化處理。

偏向鎖

偏向鎖主要為了解決在沒有競(jìng)爭(zhēng)情況下鎖的性能問題。在大多數(shù)情況下鎖鎖不僅不存在多線程競(jìng)爭(zhēng),而且總是由同一線程多次獲得,為了讓線程獲得鎖的代價(jià)更低而引入了偏向鎖。當(dāng)某個(gè)線程獲得鎖的情況,該線程是可以多次鎖住該對(duì)象,但是每次執(zhí)行這樣的操作都會(huì)因?yàn)镃AS(CPU的Compare-And-Swap指令)操作而造成一些開銷消耗性能,為了減少這種開銷,這個(gè)鎖會(huì)偏向于第一個(gè)獲得它的線程,如果在接下來的執(zhí)行過程中,該鎖沒有被其他的線程獲取,則持有偏向鎖的線程將永遠(yuǎn)不需要再進(jìn)行同步。

當(dāng)有其他線程在嘗試著競(jìng)爭(zhēng)偏向鎖時(shí),持有偏向鎖的線程就會(huì)釋放鎖。

鎖膨脹

多個(gè)或多次調(diào)用粒度太小的鎖,進(jìn)行加鎖解鎖的消耗,反而還不如一次大粒度的鎖調(diào)用來得高效。

輕量級(jí)鎖

輕量級(jí)鎖能提升程序同步性能的依據(jù)是“對(duì)于絕大部分的鎖,在整個(gè)同步周期內(nèi)都是不存在競(jìng)爭(zhēng)的”,這是一個(gè)經(jīng)驗(yàn)數(shù)據(jù)。輕量級(jí)鎖在當(dāng)前線程的棧幀中建立一個(gè)名為鎖記錄的空間,用于存儲(chǔ)鎖對(duì)象目前的指向和狀態(tài)。如果沒有競(jìng)爭(zhēng),輕量級(jí)鎖使用CAS操作避免了使用互斥量的開銷,但如果存在鎖競(jìng)爭(zhēng),除了互斥量的開銷外,還額外發(fā)生了CAS操作,因此在有競(jìng)爭(zhēng)的情況下,輕量級(jí)鎖會(huì)比傳統(tǒng)的重量級(jí)鎖更慢。

鎖的公平性

公平性的對(duì)立面是饑餓。那么什么是“饑餓”呢?如果一個(gè)線程因?yàn)槠渌€程在一直搶占著CPU而得不到CPU運(yùn)行時(shí)間,那么我們就稱該線程被“饑餓致死”。而解決饑餓的方案則被稱之為“公平性”——所有線程均可以公平地獲得CPU運(yùn)行機(jī)會(huì)。

導(dǎo)致線程饑餓主要有如下幾個(gè)原因:

高優(yōu)先級(jí)線程吞噬所有的低優(yōu)先級(jí)線程的CPU時(shí)間。我們可以為每個(gè)線程單獨(dú)設(shè)置其優(yōu)先級(jí),從1到10。優(yōu)先級(jí)越高的線程獲得CPU的時(shí)間越多。對(duì)大多數(shù)應(yīng)用來說,我們最好是不要改變其優(yōu)先級(jí)值。

線程被永久堵塞在一個(gè)等待進(jìn)入同步塊的狀態(tài)。java的同步代碼區(qū)是導(dǎo)致線程饑餓的重要因素。java的同步代碼塊并不會(huì)保證進(jìn)入它的線程的先后順序。這就意味著理論上存在一個(gè)或者多個(gè)線程在試圖進(jìn)入同步代碼區(qū)時(shí)永遠(yuǎn)被堵塞著,因?yàn)槠渌€程總是不斷優(yōu)于他獲得訪問權(quán),導(dǎo)致它一直得到不到CPU運(yùn)行機(jī)會(huì)被“饑餓致死”。

線程在等待一個(gè)本身也處于永久等待完成的對(duì)象。如果多個(gè)線程處在wait()方法執(zhí)行上,而對(duì)其調(diào)用notify()不會(huì)保證哪一個(gè)線程會(huì)獲得喚醒,任何線程都有可能處于繼續(xù)等待的狀態(tài)。因此存在這樣一個(gè)風(fēng)險(xiǎn):一個(gè)等待線程從來得不到喚醒,因?yàn)槠渌却€程總是能被獲得喚醒。

為了解決線程“饑餓”的問題,我們可以使用鎖實(shí)現(xiàn)公平性。

鎖的可重入性

我們知道當(dāng)線程請(qǐng)求一個(gè)由其它線程持有鎖的對(duì)象時(shí),該線程會(huì)阻塞,但是當(dāng)線程請(qǐng)求由自己持有鎖的對(duì)象時(shí),是否可以成功呢?答案是可以成功的,成功的保障就是線程鎖的“可重入性”。

“可重入”意味著自己可以再次獲得自己的內(nèi)部鎖,而不需要阻塞。如下:

?
1
2
3
4
5
6
7
8
9
10
11
public class Father {
 public synchronized void method(){
  //do something
 }
}
public class Child extends Father{
 public synchronized void method(){
  //do something
  super.method();
 }
}

 
如果所是不可重入的,上面的代碼就會(huì)死鎖,因?yàn)檎{(diào)用child的method(),首先會(huì)獲取父類Father的內(nèi)置鎖然后獲取Child的內(nèi)置鎖,當(dāng)調(diào)用父類的方法時(shí),需要再次后去父類的內(nèi)置鎖,如果不可重入,可能會(huì)陷入死鎖。

java多線程的可重入性的實(shí)現(xiàn)是通過每個(gè)鎖關(guān)聯(lián)一個(gè)請(qǐng)求計(jì)算和一個(gè)占有它的線程,當(dāng)計(jì)數(shù)為0時(shí),認(rèn)為該鎖是沒有被占有的,那么任何線程都可以獲得該鎖的占有權(quán)。當(dāng)某一個(gè)線程請(qǐng)求成功后,JVM會(huì)記錄該鎖的持有線程 并且將計(jì)數(shù)設(shè)置為1,如果這時(shí)其他線程請(qǐng)求該鎖時(shí)則必須等待。當(dāng)該線程再次請(qǐng)求請(qǐng)求獲得鎖時(shí),計(jì)數(shù)會(huì)+1;當(dāng)占有線程退出同步代碼塊時(shí),計(jì)數(shù)就會(huì)-1,直到為0時(shí),釋放該鎖。這時(shí)其他線程才有機(jī)會(huì)獲得該鎖的占有權(quán)。

lock及其實(shí)現(xiàn)類

java.util.concurrent.locks提供了非常靈活鎖機(jī)制,為鎖定和等待條件提供一個(gè)框架的接口和類,它不同于內(nèi)置同步和監(jiān)視器,該框架允許更靈活地使用鎖定和條件。它的類結(jié)構(gòu)圖如下:

深入解析Java并發(fā)程序中線程的同步與線程鎖的使用

ReentrantLock:一個(gè)可重入的互斥鎖,為lock接口的主要實(shí)現(xiàn)。

ReentrantReadWriteLock:

ReadWriteLock:ReadWriteLock 維護(hù)了一對(duì)相關(guān)的鎖,一個(gè)用于只讀操作,另一個(gè)用于寫入操作。

Semaphore:一個(gè)計(jì)數(shù)信號(hào)量。

Condition:鎖的關(guān)聯(lián)條件,目的是允許線程獲取鎖并且查看等待的某一個(gè)條件是否滿足。

CyclicBarrier:一個(gè)同步輔助類,它允許一組線程互相等待,直到到達(dá)某個(gè)公共屏障點(diǎn)。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产精品怡红院在线观看 | 国产一级片免费观看 | 成年人福利 | 亚洲成人影院在线观看 | 色热综合| 5555国产在线观看精品 | 四虎4hu永久免费 | 欧美三级一区 | 亚洲国产精品无码中文字满 | 欧美色图亚洲 | 欧美性色老妇人 | 性xxxx中国 | 30分钟的高清视频在线观看 | 天堂资源8中文最新版 | 日本www视频在线观看 | 亚洲国产精品ⅴa在线观看 亚洲国产高清一区二区三区 | 男人的天堂久久爱 | 国产好痛疼轻点好爽的视频 | 国产精品福利久久2020 | 午夜国产视频 | 国产精品每日在线观看男人的天堂 | 女人张开腿让男人桶视频免费大全 | 亚洲精品午夜在线观看 | 91精品国产人成网站 | 99 久久99久久精品免观看 | 性插图动态图无遮挡 | 免费观看毛片视频 | 欧美久久综合网 | 国产免费资源高清小视频在线观看 | 色老板在线视频观看 | 国产精品日韩欧美在线 | 久久成人免费大片 | 我的妹妹最近有点怪在线观看 | 国产精品免费久久久久影院 | 国产精品美女久久久久 | 明星ai人脸替换造梦在线播放 | jizz农村野外jizz农民 | 成人精品第一区二区三区 | 国产在线观看91精品一区 | 九九在线精品亚洲国产 | 午夜一个人在线观看完整版 |