<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    走自己的路

    路漫漫其修遠(yuǎn)兮,吾將上下而求索

      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      50 隨筆 :: 4 文章 :: 118 評(píng)論 :: 0 Trackbacks
     

    在這本書(shū)中文版的第219頁(yè)有個(gè)例子,講lazy load時(shí)用到double checkdouble check比直接用同步的好處是,當(dāng)Singleton初始化后,就不會(huì)有額外的同步操作。它的例子是

     1public class Singleton {
     2    private volatile static Singleton INSTANCE;
     3    
     4    private Singleton() {
     5        
     6    }

     7    
     8    public static Singleton getInstance() {
     9        if(INSTANCE == null{
    10            synchronized (Singleton.class{
    11                if(INSTANCE == null{
    12                    INSTANCE = new Singleton();
    13                }

    14            }

    15        }

    16        return INSTANCE;
    17    }

    18}

    19
     

            不幸的是,雙重檢查不會(huì)保證正常工作,因?yàn)榫幾g器會(huì)在Singleton的構(gòu)造方法被調(diào)用之前隨意給INSTANCE先付一個(gè)值。如果在INSTANCE引用被賦值之后而被初始化之前線程1被切換,線程2就會(huì)被返回一個(gè)對(duì)未初始化完全的單例類實(shí)例的引用。這樣在程序的其他方法中使用時(shí)可能會(huì)出現(xiàn)未知的錯(cuò)誤。

     

    個(gè)人一開(kāi)始認(rèn)為正確的寫(xiě)法,應(yīng)該是這樣的

     1public class SingletonNew {
     2    private volatile static SingletonNew INSTANCE;
     3    
     4    private SingletonNew() {
     5        
     6    }

     7    
     8    public static SingletonNew getInstance() {
     9        SingletonNew tempInstance = INSTANCE;
    10        if(tempInstance == null{
    11            synchronized (Singleton.class{
    12                tempInstance = INSTANCE;    //(1)
    13                if(tempInstance == null{
    14                    INSTANCE = tempInstance = new SingletonNew(); //(2)
    15                }

    16            }

    17        }

    18        return tempInstance;
    19    }

    20}

    21
     

          

         利用一個(gè)tempInstance局部變量來(lái)排除返回實(shí)例未初始化完全的情況。因?yàn)槊看闻袛嗟亩际蔷植孔兞浚總€(gè)線程都會(huì)有一個(gè)自己的tempInstance,這樣就保證每個(gè)線程的tempInstance要么是初始化完全的要么就是未初始化的,不會(huì)出現(xiàn)中間的情況。要注意的是SingletonNew(1)處是不能去掉的,比如線程構(gòu)造了一個(gè)實(shí)例,線程2此時(shí)等待在那里,線程2得到鎖,判斷tempInstance == null結(jié)果是true,又初始化了一次,這就不是單例了。(2)處的賦值順序也是不能顛倒的,如果顛倒就會(huì)出現(xiàn)和Singleton類一樣的情形。


    請(qǐng)大家詳細(xì)討論,詳細(xì)解釋一下。

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------
        其實(shí)這兩種寫(xiě)法在舊的JMM上都是錯(cuò)誤的,在新的JMM上都是對(duì)的,錯(cuò)誤的原因主要是JMM對(duì)代碼的重新排序和優(yōu)化,新的JMM又對(duì)volatile的語(yǔ)義進(jìn)行了擴(kuò)展,保證了double-check的正確性。很抱歉一開(kāi)始讓一些博友產(chǎn)生了困惑,謝謝大家的熱心的討論和回帖,我的主要問(wèn)題就是出現(xiàn)在對(duì)JMM了解不夠深入,只是碎片式的了解一些,沒(méi)有很好的了解編譯器對(duì)代碼的重新排序和優(yōu)化,當(dāng)然編譯原理課上是學(xué)過(guò)的。二又沒(méi)有很好的掌握到volatile的新的語(yǔ)義。其實(shí)對(duì)一些細(xì)節(jié)了解清楚,可以避免我們的代碼出現(xiàn)一些奇怪的問(wèn)題,特別是在多線程環(huán)境中。

     

        Jvm編譯器會(huì)對(duì)生成的代碼進(jìn)行優(yōu)化,重新排序,甚至移除它認(rèn)為不必要的代碼,volatile變量之間也是沒(méi)有順序保證的。然而jvm保證了classloader load字節(jié)碼和靜態(tài)變量初始化的同步性,所有把singleton設(shè)置為靜態(tài)變量是沒(méi)有問(wèn)題的。JMM保證了單線程執(zhí)行的效果和程序的順序是相同的。JVM對(duì)代碼的重新排序和優(yōu)化是對(duì)于程序不可見(jiàn)的,所以在例子2中我不應(yīng)該假設(shè)執(zhí)行的順序。在讀volatile變量之前,寫(xiě)行為確保執(zhí)行完畢,并且更新的值會(huì)從線程工作內(nèi)存(CPU緩存,寄存器)刷新到主內(nèi)存中,JMM禁止volatile讀入寄存器,其他線程讀取時(shí)也會(huì)重新load到工作內(nèi)存中,保證了一致性和可見(jiàn)性,避免讀取臟數(shù)據(jù)。以前一直以為volatile涉及的只是變量可見(jiàn)性問(wèn)題,或者說(shuō)對(duì)可見(jiàn)性的適用范圍沒(méi)有很好的理解,并不涉及JMM順序性和原子性問(wèn)題。新的JMM對(duì)它進(jìn)行了擴(kuò)展,它對(duì)volatile變量的重新排序也做了限制。在舊的內(nèi)存模型當(dāng)中,volatile變量的多次訪問(wèn)之間是不能重新排序的,但是它們能在和對(duì)非volatile變量訪問(wèn)代碼之間進(jìn)行重新排序,新的內(nèi)存模型不同的是,volatile訪問(wèn)行為在和非volatile變量的訪問(wèn)行為的代碼之間重新排序加了一些限制。對(duì)volatile的寫(xiě)行為就和synchronize方法或block釋放監(jiān)視器(鎖)的效果是一樣的,對(duì)volatile字段的讀操作和監(jiān)視器(鎖)的申請(qǐng)效果也是一樣的。新的模型在volatile字段訪問(wèn)上做了一些嚴(yán)格的限制,只對(duì)當(dāng)前線程可見(jiàn)的變量寫(xiě)入到volatile共享變量f后,當(dāng)其他線程讀取f后就是可見(jiàn)的。

    下面這個(gè)簡(jiǎn)單的例子:

    class VolatileExample {
     int x = 0;
     volatile boolean v = false;
     public void writer() {
        x = 42;
        v = true;
     }
     
     public void reader() {
        if (v == true) {
          //uses x - guaranteed to see 42.
        }
     }
    }

    假設(shè)當(dāng)前一個(gè)線程正在調(diào)用writer方法,其他線程正在調(diào)用reader方法,writer方法中對(duì)v的寫(xiě)行為將對(duì)x的寫(xiě)行為釋放到了內(nèi)存中,v變量的讀取,又重新從內(nèi)存中獲取了新值。因此,如果讀方法看到了v的值被設(shè)為true,也保證了它在這之前就可以看到x的新值42,但這在舊的內(nèi)存模型中是不保證的。如果v不是volatile的,編譯器可能就會(huì)對(duì)writerreader中的代碼進(jìn)行重新排序,reader方法的訪問(wèn)有可能得到的x就是0. 可見(jiàn)在新的JMM中,volatile的語(yǔ)義得到了很好的加強(qiáng),每次對(duì)volatile字段的讀和寫(xiě)可看作是都是半同步。這種順序性(happen-before關(guān)系)是針對(duì)同一個(gè)volatile字段而言的,對(duì)不同volatile字段的讀取還是沒(méi)有這種順序保證的。在新的JMM下,用volatile就可以解決問(wèn)題,線程1實(shí)例的初始化和線程2的讀取volatile變量就存在一個(gè)happen-before關(guān)系。

    JMM對(duì)順序性只是提出了一些規(guī)則,具體如何重新排序還是不得而知。

    參考文章:http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#reordering
              《JAVA Language Specification》 17.4



    posted on 2008-07-23 19:51 叱咤紅人 閱讀(2708) 評(píng)論(22)  編輯  收藏 所屬分類: Design and Analysis Pattern J2SE and JVM

    評(píng)論

    # re: 《Head First Design Pattern 單例模式》中的一個(gè)錯(cuò)誤 2008-07-23 21:20 路過(guò)
    即使第一種寫(xiě)法有問(wèn)題,你怎么能證明第二種寫(xiě)法就是對(duì)的呢?
    照你的說(shuō)法INSTANCE是一個(gè)沒(méi)有完全初始化的對(duì)象,那么tempInstance是復(fù)制的引用而已,前者沒(méi)有完全初始化后者也肯定是一樣的。我完全沒(méi)看出來(lái)多賦值一次有什么好處。
    請(qǐng)?jiān)O(shè)計(jì)一個(gè)試驗(yàn),謝謝!
      回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中的一個(gè)錯(cuò)誤 2008-07-23 23:10 Jarod
    博主是在亂說(shuō)

    private volatile static SingletonNew INSTANCE;
    static {
    System.out.println(INSTANCE); //null
    }

    就算“因?yàn)榫幾g器會(huì)在Singleton的構(gòu)造方法被調(diào)用之前隨意給INSTANCE先付一個(gè)值”成立了,代碼2不見(jiàn)得就解決了問(wèn)題  回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中的一個(gè)錯(cuò)誤[未登錄](méi) 2008-07-24 06:29 叱咤紅人
    @Jarod
    謝謝回復(fù).
    INSTANCE = new Singleton();我的理解是調(diào)用了構(gòu)造函數(shù),在構(gòu)造之前會(huì)先生成一個(gè)臨時(shí)的值,引用指向一個(gè)臨時(shí)的地方,具體以前在那里看到的也不太記得了.所以第一種方法線程1進(jìn)入構(gòu)造函數(shù)后,線程2會(huì)得到一個(gè)不是null的臨時(shí)值,所以會(huì)得到一個(gè)未初始化完全的對(duì)象.第二種方法,對(duì)全局靜態(tài)變量INSTANCE,沒(méi)有用它來(lái)作為double check的條件,而是使用了tempInstance局部變量,每個(gè)線程都會(huì)生成一個(gè)自己的tempInstance   回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中的一個(gè)錯(cuò)誤 2008-07-24 07:48 朱遠(yuǎn)翔-Apusic技術(shù)顧問(wèn)
    @叱咤紅人
    在進(jìn)入初始化之前使用的是線程同步,那么就不存在線程切換的問(wèn)題呀?   回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中的一個(gè)錯(cuò)誤 2008-07-24 08:13 ldd600
    @朱遠(yuǎn)翔-Apusic技術(shù)顧問(wèn)
    謝謝回復(fù)。
    因?yàn)椴捎昧薲ouble check,延遲了同步。所以還是存在線程切換的問(wèn)題。  回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中的一個(gè)錯(cuò)誤 2008-07-24 08:46 5452
    double check這個(gè)東西,現(xiàn)在說(shuō)不清楚,這種方法沒(méi)有辦法確定就是單例。
    JVM建立對(duì)象的過(guò)程是這樣的:1、先分配一塊內(nèi)存,2、然后把內(nèi)存地址賦值給對(duì)象的引用,3、然后調(diào)用類的構(gòu)造函數(shù),生成對(duì)象。
    如果一個(gè)線程執(zhí)行到第二步的時(shí)候,另外一個(gè)線程進(jìn)入這個(gè)方法,這個(gè)時(shí)候INSTANCE已經(jīng)不是空的了,但是實(shí)際上還沒(méi)有初始化,這樣的話,一定會(huì)出問(wèn)題的~
      回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中的一個(gè)錯(cuò)誤 2008-07-24 09:24 路過(guò)
    樓主所提出的問(wèn)題我可以理解,可是無(wú)法理解
    “ if(INSTANCE == null) {”

    “ SingletonNew tempInstance = INSTANCE;
    if(tempInstance == null) {”
    這兩句會(huì)得到不同的判斷。
    如果INSTANCE沒(méi)有完全初始話,tempInstance也肯定是一樣啊。雖然“每個(gè)線程都會(huì)生成一個(gè)自己的tempInstance”,其實(shí)這些tempInstance和INSTANCE沒(méi)有區(qū)別,它們是不同的引用,但是指向同一個(gè)對(duì)象。
      回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中的一個(gè)錯(cuò)誤 2008-07-24 09:29 ldd600
    @路過(guò)
    謝謝回復(fù)
    每個(gè)線程生成自己的tempInstance是指這句
    INSTANCE = tempInstance = new SingletonNew(); //(2)
    這句保證了INSTANCE的構(gòu)造的完全性。  回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中的一個(gè)錯(cuò)誤 2008-07-24 09:38 yswift
    JAVA不支持double check,不管怎么修改,只要用到double check都是錯(cuò)的,在C++中,書(shū)中的例子是完全可以正常工作的。  回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中的一個(gè)錯(cuò)誤 2008-07-24 10:07 路人
    好像都沒(méi)說(shuō)道正點(diǎn)上,注意volatile關(guān)鍵字。  回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中的一個(gè)錯(cuò)誤 2008-07-24 10:29 白色天堂
    這段代碼在jdk1.5之后完全沒(méi)有問(wèn)題。之前的版本可能出問(wèn)題。

    你也沒(méi)有理解出錯(cuò)的原因,所作的改動(dòng)完全是畫(huà)蛇添足。  回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中的一個(gè)錯(cuò)誤 2008-07-24 11:06 dennis
    無(wú)語(yǔ)了,沒(méi)看到volatile關(guān)鍵字嗎?  回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中的一個(gè)錯(cuò)誤 2008-07-24 11:07 dennis
    @白色天堂
    也不能說(shuō)完全沒(méi)問(wèn)題,有的jvm實(shí)現(xiàn)在volatile的語(yǔ)義上還是有問(wèn)題的,只能說(shuō)在sun jdk1.5及以后版本是沒(méi)有問(wèn)題的。  回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中double check有問(wèn)題嗎? 2008-07-24 12:38 路過(guò)
    麻煩樓上的講一下為什么
    INSTANCE = tempInstance = new SingletonNew(); //(2)
    這句保證了INSTANCE的構(gòu)造的完全性。
    謝謝。  回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中double check有問(wèn)題嗎? 2008-07-24 12:42 路過(guò)
    volatile在這段程序里起了什么作用呢?
    樓主說(shuō)的是得到了一個(gè)引用但是引用指向的對(duì)象是沒(méi)有完全初始化的,又不是說(shuō)對(duì)象已經(jīng)初始化了還是有程序得到了null的引用。
    麻煩樓上的解釋一下,謝謝。  回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中double check有問(wèn)題嗎? 2008-07-24 13:09 zhuxing
    @yswift

    yswift同志說(shuō)的一針見(jiàn)血!  回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中double check有問(wèn)題嗎? 2008-07-25 09:32 dennis
    http://www.ibm.com/developerworks/java/library/j-dcl.html?loc=j

    看看這篇文章,俺就不多說(shuō)了。原因就在于JMM模型的out-of-order writes問(wèn)題。jdk5通過(guò)正確的實(shí)現(xiàn)volatile語(yǔ)義能保證對(duì)聲明為volatile的變量的讀和寫(xiě)不會(huì)被后續(xù)的讀和寫(xiě)所重排序,因而解決了這個(gè)問(wèn)題。  回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中double check有問(wèn)題嗎? 2008-07-25 11:09 路過(guò)
    The best solution to this problem is to accept synchronization or use a static field.
    多謝dennis,學(xué)習(xí)了。  回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中double check有問(wèn)題嗎? 2008-07-26 21:44 叱咤紅人
    謝謝大家尤其是dennis的熱情討論和回復(fù),其實(shí)這兩種寫(xiě)法在舊的JMM上都是錯(cuò)誤的,在新的JMM上都是對(duì)的,我主要還是沒(méi)有對(duì)JMM有更深入的理解,抱歉,繼續(xù)努力好好工作,好好學(xué)習(xí),大家分享。  回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中double check有問(wèn)題嗎? 2008-07-26 21:46 叱咤紅人
    其實(shí)這兩種寫(xiě)法在舊的JMM上都是錯(cuò)誤的,在新的JMM上都是對(duì)的,錯(cuò)誤的原因主要是JMM對(duì)代碼的重新排序和優(yōu)化,新的JMM又對(duì)volatile的語(yǔ)義進(jìn)行了擴(kuò)展,保證了double-check的正確性。很抱歉一開(kāi)始讓一些博友產(chǎn)生了困惑,謝謝大家的熱心的討論和回帖,我的主要問(wèn)題就是出現(xiàn)在對(duì)JMM了解不夠深入,只是碎片式的了解一些,沒(méi)有很好的了解編譯器對(duì)代碼的重新排序和優(yōu)化,當(dāng)然編譯原理課上是學(xué)過(guò)的。二又沒(méi)有很好的掌握到volatile的新的語(yǔ)義。其實(shí)對(duì)一些細(xì)節(jié)了解清楚,可以避免我們的代碼出現(xiàn)一些奇怪的問(wèn)題,特別是在多線程環(huán)境中。


    Jvm編譯器會(huì)對(duì)生成的代碼進(jìn)行優(yōu)化,重新排序,甚至移除它認(rèn)為不必要的代碼,volatile變量之間也是沒(méi)有順序保證的。然而jvm保證了classloader load字節(jié)碼和靜態(tài)變量初始化的同步性,所有把singleton設(shè)置為靜態(tài)變量是沒(méi)有問(wèn)題的。JMM保證了單線程執(zhí)行的效果和程序的順序是相同的。JVM對(duì)代碼的重新排序和優(yōu)化是對(duì)于程序不可見(jiàn)的,所以在例子2中我不應(yīng)該假設(shè)執(zhí)行的順序。在讀volatile變量之前,寫(xiě)行為確保執(zhí)行完畢,并且更新的值會(huì)從線程工作內(nèi)存(CPU緩存,寄存器)刷新到主內(nèi)存中,JMM禁止volatile讀入寄存器,其他線程讀取時(shí)也會(huì)重新load到工作內(nèi)存中,保證了一致性和可見(jiàn)性,避免讀取臟數(shù)據(jù)。以前一直以為volatile涉及的只是變量可見(jiàn)性問(wèn)題,或者說(shuō)對(duì)可見(jiàn)性的適用范圍沒(méi)有很好的理解,并不涉及JMM順序性和原子性問(wèn)題。新的JMM對(duì)它進(jìn)行了擴(kuò)展,它對(duì)volatile變量的重新排序也做了限制。在舊的內(nèi)存模型當(dāng)中,volatile變量的多次訪問(wèn)之間是不能重新排序的,但是它們能在和對(duì)非volatile變量訪問(wèn)代碼之間進(jìn)行重新排序,新的內(nèi)存模型不同的是,volatile訪問(wèn)行為在和非volatile變量的訪問(wèn)行為的代碼之間重新排序加了一些限制。對(duì)volatile的寫(xiě)行為就和synchronize方法或block釋放監(jiān)視器(鎖)的效果是一樣的,對(duì)volatile字段的讀操作和監(jiān)視器(鎖)的申請(qǐng)效果也是一樣的。新的模型在volatile字段訪問(wèn)上做了一些嚴(yán)格的限制,只對(duì)當(dāng)前線程可見(jiàn)的變量寫(xiě)入到volatile共享變量f后,當(dāng)其他線程讀取f后就是可見(jiàn)的。

    下面這個(gè)簡(jiǎn)單的例子:

    class VolatileExample {
    int x = 0;
    volatile boolean v = false;
    public void writer() {
    x = 42;
    v = true;
    }

    public void reader() {
    if (v == true) {
    //uses x - guaranteed to see 42.
    }
    }
    }
    假設(shè)當(dāng)前一個(gè)線程正在調(diào)用writer方法,其他線程正在調(diào)用reader方法,writer方法中對(duì)v的寫(xiě)行為將對(duì)x的寫(xiě)行為釋放到了內(nèi)存中,v變量的讀取,又重新從內(nèi)存中獲取了新值。因此,如果讀方法看到了v的值被設(shè)為true,也保證了它在這之前就可以看到x的新值42,但這在舊的內(nèi)存模型中是不保證的。如果v不是volatile的,編譯器可能就會(huì)對(duì)writer和reader中的代碼進(jìn)行重新排序,reader方法的訪問(wèn)有可能得到的x就是0. 可見(jiàn)在新的JMM中,volatile的語(yǔ)義得到了很好的加強(qiáng),每次對(duì)volatile字段的讀和寫(xiě)可看作是都是半同步。這種順序性(happen-before關(guān)系)是針對(duì)同一個(gè)volatile字段而言的,對(duì)不同volatile字段的讀取還是沒(méi)有這種順序保證的。在新的JMM下,用volatile就可以解決問(wèn)題,線程1實(shí)例的初始化和線程2的讀取volatile變量就存在一個(gè)happen-before關(guān)系。
      回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中double check有問(wèn)題嗎? 2008-07-26 21:53 zxbyh
    不用去研究這個(gè)!
    使用餓漢單例模式就可以了.

    <<java 與模式>>  回復(fù)  更多評(píng)論
      

    # re: 《Head First Design Pattern 單例模式》中double check有問(wèn)題嗎?[未登錄](méi) 2008-08-08 13:26 Chris
    不管哪種方法,在多機(jī)的情況下依然還是解決不了單例的問(wèn)題,現(xiàn)在機(jī)器那么廉價(jià),那點(diǎn)延遲初始化所帶來(lái)的效率是微乎其微的,完全不需要。  回復(fù)  更多評(píng)論
      

    主站蜘蛛池模板: 亚洲高清无在码在线电影不卡| 久久精品国产亚洲av成人| 国产精品亚洲专区无码牛牛| 亚洲av成人一区二区三区观看在线| 日韩大片免费观看视频播放| 一本色道久久88亚洲精品综合| 亚洲日本精品一区二区| 亚洲国产成人91精品| 亚洲天堂一区在线| 亚洲国产一区二区三区在线观看 | 精品国产亚洲第一区二区三区| 一级做a爱片特黄在线观看免费看| 亚洲av片在线观看| 国产va免费观看| 成人免费ā片在线观看| 91热久久免费精品99| 日韩视频免费一区二区三区| 久久这里只有精品国产免费10| jjizz全部免费看片| 一区二区三区四区免费视频| 日本一区二区免费看| 丁香花在线观看免费观看| 亚洲国产精品碰碰| 中文字幕不卡亚洲| 亚洲图片中文字幕| 特a级免费高清黄色片| 91福利视频免费观看| 国产免费av片在线无码免费看| 日韩免费在线观看| 亚洲VA中文字幕无码毛片 | 亚洲综合精品一二三区在线| 亚洲人成自拍网站在线观看| a级毛片免费全部播放无码| 三年片在线观看免费观看高清电影| 亚洲男人的天堂在线va拉文| 亚洲无砖砖区免费| 99免费精品视频| 精品久久久久久久免费加勒比| 久久亚洲国产成人亚| 亚洲图片激情小说| 国色精品va在线观看免费视频|