在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

糟糕,被SimpleDateFormat坑到啦!

京東云 ? 來源:jf_75140285 ? 作者:jf_75140285 ? 2024-09-06 09:45 ? 次閱讀

1. 問題背景

問題的背景是這樣的,在最近需求開發(fā)中遇到需要將給定目標(biāo)數(shù)據(jù)通過某一固定的計量規(guī)則進(jìn)行過濾并打標(biāo)生成明細(xì)數(shù)據(jù),其中發(fā)現(xiàn)存在一筆目標(biāo)數(shù)據(jù)的時間在不符合現(xiàn)有日期規(guī)則的條件下,還是通過了規(guī)則引擎的匹配打標(biāo)操作。故而需要對該錯誤匹配場景進(jìn)行排查,定位根本原因所在。

2. 排查思路

2.1 數(shù)據(jù)定位

在開始排查問題之初,先假定現(xiàn)有的Aviator規(guī)則引擎能夠?qū)ΜF(xiàn)有的數(shù)據(jù)進(jìn)行正常的匹配打標(biāo),查詢在存在問題數(shù)據(jù)(圖中紅框所示)同一時刻進(jìn)行規(guī)則匹配時的數(shù)據(jù)都有哪些。發(fā)現(xiàn)存在五筆數(shù)據(jù)在同一時刻進(jìn)行規(guī)則匹配落庫。

wKgaombaXpCANXfmAAGe5bR-pqY435.png

繼續(xù)查詢具體的匹配規(guī)則表達(dá)式,發(fā)現(xiàn)針對loanPayTime時間區(qū)間在[2022-07-16 00:00:00, 2023-05-11 23:59:59]的范圍內(nèi)進(jìn)行匹配,目標(biāo)數(shù)據(jù)的時間為2023-09-19 11:27:29,理論上應(yīng)該不會被匹配到。

wKgZombaXpGAe-HlAABHT4Fj8qw463.png

但是觀測匹配打標(biāo)的明細(xì)數(shù)據(jù)發(fā)現(xiàn)確實打標(biāo)成功了(如紅框所示)。

wKgaombaXpKABZ6IAAGh1Bn0M7E195.png

所以重新回到最初的和目標(biāo)數(shù)據(jù)同時落庫的五筆數(shù)據(jù)發(fā)現(xiàn),這五筆數(shù)據(jù)的loanPayTime時間確實在規(guī)則[2022-07-16 00:00:00, 2023-05-11 23:59:59]之內(nèi),所以在想有沒有可能是在目標(biāo)數(shù)據(jù)匹配規(guī)則引擎,其它的五筆數(shù)據(jù)中的其中一筆對該數(shù)據(jù)進(jìn)行了修改導(dǎo)致誤匹配到了這個規(guī)則。順著這個思路,首先需要確認(rèn)下Aviator規(guī)則引擎在并發(fā)場景下是否線程安全的。

wKgZombaXpaAPKazAAG9HT1yXuU440.png

2.2 規(guī)則引擎

由于在需求中使用到用于給數(shù)據(jù)匹配打標(biāo)的是Aviator規(guī)則引擎,所以第一直覺是懷疑Aviator規(guī)則引擎在并發(fā)的場景中可能會存在線程不安全的情況。

wKgaombaXpeAFAwrAACPrAnrQf0551.png

首先簡單介紹下Aviator規(guī)則引擎是什么,Aviator是一個高性能的、輕量級java語言實現(xiàn)的表達(dá)式求值引擎,主要用于各種表達(dá)式的動態(tài)求值,相較于其它的開源可用的規(guī)則引擎而言,Aviator的設(shè)計目標(biāo)是輕量級和高性能 ,相比于Groovy、JRuby的笨重,Aviator非常小,加上依賴包也才450K,不算依賴包的話只有70K;

當(dāng)然,Aviator的語法是受限的,它不是一門完整的語言,而只是語言的一小部分集合。其次,Aviator的實現(xiàn)思路與其他輕量級的求值器很不相同,其他求值器一般都是通過解釋的方式運行,而Aviator則是直接將表達(dá)式編譯成Java字節(jié)碼,交給JVM去執(zhí)行。簡單來說,Aviator的定位是介于Groovy這樣的重量級腳本語言和IKExpression這樣的輕量級表達(dá)式引擎之間。(具體Aviator的相關(guān)介紹不是本文的重點,具體可參見)

通過查閱相關(guān)資料發(fā)現(xiàn),Aviator中的AviatorEvaluator.execute() 方法本身是線程安全的,也就是說只要表達(dá)式執(zhí)行邏輯和傳入的env是線程安全的,理論上是不會出現(xiàn)并發(fā)場景下線程不安全問題的。(詳見)

2.3 匹配規(guī)則引擎的env

wKgZombaXpiAbcE5AABTqU--LnI055.png

通過前面Aviator的相關(guān)資料發(fā)現(xiàn)傳入的env如果在多線程場景下不安全也會導(dǎo)致最終的結(jié)果是錯誤的,故而定位使用的env發(fā)現(xiàn)使用的是HashMap,該集合類確實是線程不安全的(具體可詳見),但是線程不安全的前提是多個線程同時對其進(jìn)行修改,定位代碼發(fā)現(xiàn)在每次調(diào)用方式時都會重新生成一個HashMap,故而應(yīng)該不會是由于這個線程不安全類導(dǎo)致的。

wKgaombaXpmABWGSAADNnSDuIgY560.png

繼續(xù)定位發(fā)現(xiàn),loanPayTime這個字段在進(jìn)行Aviator規(guī)則引擎匹配前使用SimpleDateFormat進(jìn)行了格式化,所以有可能是由于該類的線程不安全導(dǎo)致的數(shù)據(jù)錯亂問題,但是這個類應(yīng)該只是對日期進(jìn)行格式化處理,難不成還能影響最終的數(shù)據(jù)。帶著這個疑問查詢資料發(fā)現(xiàn),emm確實是線程不安全的。

wKgZombaXpqAJhg_AAKEKTD57Ws016.png

好家伙,嫌疑對象目前已經(jīng)有了,現(xiàn)在就是尋找相關(guān)證據(jù)來佐證了。

3. SimpleDateFormat 還能線程不安全?

3.1 先寫個demo試試

話不多說,直接去測試一下在并發(fā)場景下,SimpleDateFormat類會不會對需要格式化的日期進(jìn)行錯亂格式化。先模擬一個場景,對多線程并發(fā)場景下格式化日期,即在[0,9]的數(shù)據(jù)范圍內(nèi),在偶數(shù)情況下對2024年1月23日進(jìn)行格式化,在奇數(shù)情況下對2024年1月22日進(jìn)行格式化,然后觀測日志打印效果。

import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ThreadSafeDateFormatDemo {
    static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(10);
        LocalDateTime startDateTime = LocalDateTime.now();
        Date date = new Date();
        for (int i = 0; i < 1000; i++) {
            int finalI = i;
            executor.submit(() -?> {
                try {
                    if (finalI % 2 == 0) {

                        String formattedDate = dateFormat.format(date);
                        //第一種
//                        String formattedDate = DateUtil.formatDate(date);
                        //第二種
//                        String formattedDate = DateSyncUtil.formatDate(date);
                        //第三種
//                        String formattedDate = ThreadLocalDateUtil.formatDate(date);
                        System.out.println("線程 " + Thread.currentThread().getName() + " 時間為: " + formattedDate + " 偶數(shù)i:" + finalI);
                    } else {
                        Date now = new Date();
                        now.setTime(now.getTime() - TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS));
                        String formattedDate = dateFormat.format(now);
                        //第一種
//                        String formattedDate = DateUtil.formatDate(now);
                        //第二種
//                        String formattedDate = DateSyncUtil.formatDate(now);
                        //第三種
//                        String formattedDate = ThreadLocalDateUtil.formatDate(now);
                        System.out.println("線程 " + Thread.currentThread().getName() + " 時間為: " + formattedDate + " 奇數(shù)i:" + finalI);
                    }

                } catch (Exception e) {
                    System.err.println("線程 " + Thread.currentThread().getName() + " 出現(xiàn)了異常: " + e.getMessage());
                }
            });
        }

        executor.shutdown();
        try {
            executor.awaitTermination(30, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 計算總耗時
        LocalDateTime endDateTime = LocalDateTime.now();
        Duration duration = Duration.between(startDateTime, endDateTime);
        System.out.println("所有任務(wù)執(zhí)行完畢,總耗時: " + duration.toMillis() + " 毫秒");
    }
}

具體demo代碼如上所示,執(zhí)行結(jié)果如下,理論上來說應(yīng)該是2024年1月23日2024年1月22日打印日志的次數(shù)各5次。實際結(jié)果發(fā)現(xiàn)在偶數(shù)的場景下仍然會出現(xiàn)打印格式化2024年1月22日的場景。明顯出現(xiàn)了數(shù)據(jù)錯亂賦值的問題,所以到這里大概可以基本確定就是SimpleDateFormat類在并發(fā)場景下線程不安全導(dǎo)致的

wKgZombaXp2Acjb2AAEwnhsTG2I866.png

3.2 SimpleDateFormat為什么線程不安全?

查詢相關(guān)資料發(fā)現(xiàn),從SimpleDateFormat類提供的接口來看,實在讓人看不出它與線程安全有什么關(guān)系,進(jìn)入SimpleDateFormat源碼發(fā)現(xiàn)類上面確實存在注釋提醒:意思就是, SimpleDateFormat中的日期格式不是同步的。推薦(建議)為每個線程創(chuàng)建獨立的格式實例。如果多個線程同時訪問一個格式,則它必須保持外部同步。

wKgaombaXp6ARHuCAAGXORfBsp0840.png

繼續(xù)分析源碼發(fā)現(xiàn),SimpleDateFormat線程不安全的真正原因是繼承了DateFormat,DateFormat中定義了一個protected屬性的 Calendar類的對象:calendar。由于Calendar類的概念復(fù)雜,牽扯到時區(qū)與本地化等等,jdk的實現(xiàn)中使用了成員變量來傳遞參數(shù),這就造成在多線程的時候會出現(xiàn)錯誤。

wKgZombaXqCALSSGAAGEsqLatYw884.png

注意到在format方法中有一段如下代碼:

 public StringBuffer format(Date date, StringBuffer toAppendTo,
                               FieldPosition pos)
    {
        pos.beginIndex = pos.endIndex = 0;
        return format(date, toAppendTo, pos.getFieldDelegate());
    }

    // Called from Format after creating a FieldDelegate
    private StringBuffer format(Date date, StringBuffer toAppendTo,
                                FieldDelegate delegate) {
        // Convert input date to time field list
        calendar.setTime(date);

        boolean useDateFormatSymbols = useDateFormatSymbols();

        for (int i = 0; i < compiledPattern.length; ) {
            int tag = compiledPattern[i] >>> 8;
            int count = compiledPattern[i++] & 0xff;
            if (count == 255) {
                count = compiledPattern[i++] 

calendar.setTime(date)這條語句改變了calendar,稍后,calendar還會用到(在subFormat方法里),而這就是引發(fā)問題的根源。

想象一下,在一個多線程環(huán)境下,有兩個線程持有了同一個SimpleDateFormat的實例,分別調(diào)用format方法: 線程1調(diào)用format方法,改變了calendar這個字段。 中斷來了。 線程2開始執(zhí)行,它也改變了calendar。 又中斷了。 線程1回來了,此時,calendar已然不是它所設(shè)的值,而是走上了線程2設(shè)計的道路。

如果多個線程同時爭搶calendar對象,則會出現(xiàn)各種問題,時間不對線程掛死等等。 分析一下format的實現(xiàn),我們不難發(fā)現(xiàn),用到成員變量calendar,唯一的好處,就是在調(diào)用subFormat時,少了一個參數(shù),卻帶來了這許多的問題。

其實,只要在這里用一個局部變量,一路傳遞下去,所有問題都將迎刃而解。 這個問題背后隱藏著一個更為重要的問題–無狀態(tài):無狀態(tài)方法的好處之一,就是它在各種環(huán)境下,都可以安全的調(diào)用。衡量一個方法是否是有狀態(tài)的,就看它是否改動了其它的東西,比如全局變量,比如實例的字段。format方法在運行過程中改動了SimpleDateFormat的calendar字段,所以,它是有狀態(tài)的。

4. 如何解決?

4.1 每次在需要時新創(chuàng)建實例

在需要進(jìn)行格式化日期的地方新建一個實例,不管什么時候,將有線程安全問題的對象由共享變?yōu)榫植克接卸寄鼙苊舛嗑€程問題,不過也加重了創(chuàng)建對象的負(fù)擔(dān)。在一般情況下,這樣其實對性能影響比不是很明顯的。代碼示例如下。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author 
 * @date 2024/1/23 20:04
 */


public class DateUtil {

    public static String formatDate(Date date) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    public static Date parse(String strDate) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.parse(strDate);
    }
}?

4.2 同步SimpleDateFormat對象

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author 
 * @date 2024/1/23 20:04
 */


public class DateSyncUtil {

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static String formatDate(Date date) throws ParseException {
        synchronized (sdf) {
            return sdf.format(date);
        }
    }

    public static Date parse(String strDate) throws ParseException {
        synchronized (sdf) {
            return sdf.parse(strDate);
        }
    }
}

說明:當(dāng)線程較多時,當(dāng)一個線程調(diào)用該方法時,其他想要調(diào)用此方法的線程就要block,多線程并發(fā)量大的時候會對性能有一定的影響。

4.3 ThreadLocal

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ConcurrentDateUtil {

    private static ThreadLocal threadLocal = new ThreadLocal() {
        @Override
        protected DateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
    };

    public static Date parse(String dateStr) throws ParseException {
        return threadLocal.get().parse(dateStr);
    }

    public static String format(Date date) {
        return threadLocal.get().format(date);
    }
}

另一種寫法

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author 
 * @date 2024/1/23 15:44
 * @description 線程安全的日期處理類
 */


public class ThreadLocalDateUtil {
    /**
     * 日期格式
     */
    private static final String date_format = "yyyy-MM-dd HH:mm:ss";
    /**
     * 線程安全處理
     */
    private static ThreadLocal threadLocal = new ThreadLocal();

    /**
     * 線程安全處理
     */
    public static DateFormat getDateFormat() {
        DateFormat df = threadLocal.get();
        if (df == null) {
            df = new SimpleDateFormat(date_format);
            threadLocal.set(df);
        }
        return df;
    }

    /**
     * 線程安全處理日期格式化
     */
    public static String formatDate(Date date) {
        return getDateFormat().format(date);
    }

    /**
     * 線程安全處理日期解析
     */
    public static Date parse(String strDate) throws ParseException {
        return getDateFormat().parse(strDate);
    }
}

說明:使用ThreadLocal, 也是將共享變量變?yōu)楠毾恚€程獨享肯定能比方法獨享在并發(fā)環(huán)境中能減少不少創(chuàng)建對象的開銷。如果對性能要求比較高的情況下,一般推薦使用這種方法

4.4 拋棄JDK,使用其他類庫中的時間格式化類

?使用

Apache commons

里的

FastDateFormat

,宣稱是既快又線程安全的SimpleDateFormat, 可惜它

只能

對日期進(jìn)行format,

不能

對日期串進(jìn)行解析。?使用

Joda-Time

類庫來處理時間相關(guān)問題。

5. 性能比較

通過追加時間監(jiān)控,將原有數(shù)據(jù)范圍擴充到[0,999],線程池保留10個線程不變,觀察三種情況下性能情況。

?第一種:耗時40ms

wKgaombaXqCAH1PyAAIHquMz2Lk923.png

?第二種:耗時33ms

wKgZombaXqGAEfNnAAH-Naeabi0246.png

?第三種:耗時30ms

wKgaombaXqOAexakAAIU_W9WkC4323.png

通過性能壓測發(fā)現(xiàn)4.3中的ThreadLocal性能最優(yōu),耗時30ms,4.1每次新創(chuàng)建實例性能最差,需要耗時40ms,當(dāng)然了在極致的高并發(fā)場景下提升效果應(yīng)該會更加明顯。性能問題不是本文探討的重點,在此不多做贅述。

6. 總結(jié)

Ok,以上就是針對本次問題排查的主要思路及流程,這個我剛開始的排查思路也一直局限于規(guī)則引擎的線程不安全或者是傳入的env(由于使用的是HashMap)線程不安全,還是受到組內(nèi)大佬的啟發(fā)和幫助才進(jìn)一步去分析SimpleDateFormat類可能會存在線程不安全。本次問題排查確實提供一個經(jīng)驗打破常規(guī)思路,比如SimpleDateFormat類看起來只是對日期進(jìn)行格式化,很難和在并發(fā)場景下線程不安全會導(dǎo)致數(shù)據(jù)錯亂關(guān)聯(lián)起來。以上。

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2967

    瀏覽量

    104751
  • hashmap
    +關(guān)注

    關(guān)注

    0

    文章

    14

    瀏覽量

    2288
收藏 人收藏

    評論

    相關(guān)推薦

    老板了,,,

    今天去廣州賽格那買一些元件。。如電阻啊,電容啊,三極管。。。第一次買這些東西,那的老板狂吃,卻不知道。。哎,買回來上網(wǎng)一看那些價格。。。果然是交學(xué)費了。。。。。
    發(fā)表于 11-18 13:10

    方波上下邊沿均出現(xiàn)糟糕的抖動

    光電編碼器輸出方波上下邊沿均出現(xiàn)糟糕的抖動?會不會是電機影響?求解?謝謝!
    發(fā)表于 04-22 20:57

    賺經(jīng)驗積分

    一分錢難倒英雄好漢這不是嗎沒積分下載資料求支招~~~~
    發(fā)表于 07-08 15:03

    使用閃存最糟糕的環(huán)境是什么?

    使用閃存最糟糕的環(huán)境是什么? 以上來自于百度翻譯 以下為原文What kind of environment is the worst in using flash memory?
    發(fā)表于 12-07 14:39

    爛代碼你能忍嗎?優(yōu)秀的代碼VS糟糕的代碼

    糟糕的代碼原來那么不堪一擊。
    的頭像 發(fā)表于 03-30 10:09 ?4404次閱讀
    爛代碼你能忍嗎?優(yōu)秀的代碼VS<b class='flag-5'>糟糕</b>的代碼

    小米華為又蘋果,LG才是最大的“親王”?

    過硬的產(chǎn)品形象,出現(xiàn)多個問題產(chǎn)品。比如,華為手機Mate20 Pro就被LG的不淺,而蘋果似乎也馬上要成為下一個的對象。那么這到底是怎么回事,為何LG才是最大的“親王”? 本文
    的頭像 發(fā)表于 11-17 11:34 ?590次閱讀

    怎樣對待水平糟糕的程序員

    這些年遇到了很多糟糕的程序員,其實真正是寫程序料的人,普通IT公司大概只占1/3左右吧,其實有2/3的人都太適合當(dāng)程序員,還不如早點兒改行該干啥就干啥了,其中有1/10的人往往是相對比較糟糕的。
    的頭像 發(fā)表于 12-28 14:52 ?1315次閱讀

    網(wǎng)購鼠標(biāo)和鍵盤時這幾個點最容易

    本篇給大家?guī)淼氖墙衲?15電商廉價的爹電競鍵鼠篇。很多學(xué)生黨或者預(yù)算很低但又喜愛玩電競游戲的朋友在某寶購買鍵盤和鼠標(biāo)時,最容易掉進(jìn)以下兩種鍵鼠的內(nèi)。
    的頭像 發(fā)表于 03-15 10:36 ?8487次閱讀

    購買組裝電腦和配件有哪些方法避免

    越來越多的電腦小白入被騙,繼而維權(quán)困難,只能是啞巴吃黃連有苦說不出。其實網(wǎng)購有決竅,掌握以下幾點我們就能避免
    的頭像 發(fā)表于 12-07 11:23 ?6511次閱讀

    使用Redis時可能遇到哪些「」?

    這篇文章,我想和你聊一聊在使用 Redis 時,可能會踩到的「」。 如果你在使用 Redis 時,也遇到過以下這些「詭異」的場景,那很大概率是踩到「」了: 明明一個 key 設(shè)置了過期時間
    的頭像 發(fā)表于 04-09 11:19 ?2305次閱讀
    使用Redis時可能遇到哪些「<b class='flag-5'>坑</b>」?

    嵌入式Linux踩記錄

    Linux踩記錄記錄Linux學(xué)習(xí)過程踩過的與如何解決踩1解決方法:F10進(jìn)入BIOS使能虛擬化技術(shù)
    發(fā)表于 11-01 17:21 ?10次下載
    嵌入式Linux踩<b class='flag-5'>坑</b>記錄

    Redis分布式鎖的10個

    這塊代碼是有 的,因為setnx和expire兩個命令是分開寫的,并不是原子操作!如果剛要執(zhí)行完setnx加鎖,正要執(zhí)行expire設(shè)置過期時間時,進(jìn)程crash或者要重啟維護(hù)了,那么這個鎖就“長生不老 ”了,別的線程永遠(yuǎn)獲取不到鎖
    的頭像 發(fā)表于 01-10 10:38 ?651次閱讀

    PCB設(shè)計避指南

    本文就重點講解PCB設(shè)計避指南,99%的PCB工程師容易忽略的!點進(jìn)來避 大家在PCB設(shè)計中都踩過哪些,一起來圍觀這些奇奇怪怪的
    的頭像 發(fā)表于 03-20 18:20 ?1179次閱讀
    PCB設(shè)計避<b class='flag-5'>坑</b>指南

    【避指南】電容耐壓降額裕量不合理導(dǎo)致電容頻繁擊穿

    【避指南】電容耐壓降額裕量不合理導(dǎo)致電容頻繁擊穿
    的頭像 發(fā)表于 11-23 09:04 ?2043次閱讀
    【避<b class='flag-5'>坑</b>指南】電容耐壓降額裕量不合理導(dǎo)致電容頻繁<b class='flag-5'>被</b>擊穿

    問爆的避方法!——天線設(shè)計

    天線設(shè)計,也是4G模組應(yīng)用中最容易踩的地方。今天主要分享討論Air700ECQ/EAQ/EMQ系列模組,天線管腳4G天線之間的電路設(shè)計和走線規(guī)則。 ? Air700ECQ/EAQ/EMQ模組屬于
    的頭像 發(fā)表于 12-26 16:45 ?66次閱讀
    <b class='flag-5'>被</b>問爆的避<b class='flag-5'>坑</b>方法!——天線設(shè)計
    主站蜘蛛池模板: 色老太视频| 色com| 一级一级毛片免费播放| 5060午夜一级| 国产精品久久女同磨豆腐| 福利毛片| 一区二区免费| 调教r18车肉高h男男| 五月天婷婷导航| 欧美一区二区三区在线观看免费| 六月综合网| 成人涩涩网站| 视频在线精品| 91福利国产在线观看网站| 一区二区三区在线观看免费| 伊人久久大香线蕉影院95| 久久久久久久久综合| 亚洲第七页| 丁香婷婷综合网| 五月婷婷之婷婷| 美女被羞羞产奶视频网站| 手机看片1024日韩| 在线欧美成人| 欧美18videosex性欧美69| free欧美性| 国产精品午夜久久| 亚洲不卡网| 久草a视频| 天堂资源最新版在线官网| 免费大片看黄在观看| 色多多免费在线观看| 午夜小视频在线| 88av在线视频| 色狠狠一区二区| 人人干人人玩| 在线成人免费观看国产精品| 欧美一二| 日一日操一操| 欧洲精品不卡1卡2卡三卡| 日本www网站| 午夜精品视频在线观看美女|