国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频

線程池是如何重復(fù)利用空閑的線程來(lái)執(zhí)行任務(wù)的?

共 44810字,需瀏覽 90分鐘

 ·

2021-03-17 09:53

在Java開(kāi)發(fā)中,經(jīng)常需要?jiǎng)?chuàng)建線程去執(zhí)行一些任務(wù),實(shí)現(xiàn)起來(lái)也非常方便,但如果并發(fā)的線程數(shù)量很多,并且每個(gè)線程都是執(zhí)行一個(gè)時(shí)間很短的任務(wù)就結(jié)束了,這樣頻繁創(chuàng)建線程就會(huì)大大降低系統(tǒng)的效率,因?yàn)轭l繁創(chuàng)建線程和銷毀線程需要時(shí)間。此時(shí),我們很自然會(huì)想到使用線程池來(lái)解決這個(gè)問(wèn)題。

使用線程池的好處:

  • 降低資源消耗。java中所有的池化技術(shù)都有一個(gè)好處,就是通過(guò)復(fù)用池中的對(duì)象,降低系統(tǒng)資源消耗。設(shè)想一下如果我們有n多個(gè)子任務(wù)需要執(zhí)行,如果我們?yōu)槊總€(gè)子任務(wù)都創(chuàng)建一個(gè)執(zhí)行線程,而創(chuàng)建線程的過(guò)程是需要一定的系統(tǒng)消耗的,最后肯定會(huì)拖慢整個(gè)系統(tǒng)的處理速度。而通過(guò)線程池我們可以做到復(fù)用線程,任務(wù)有多個(gè),但執(zhí)行任務(wù)的線程可以通過(guò)線程池來(lái)復(fù)用,這樣減少了創(chuàng)建線程的開(kāi)銷,系統(tǒng)資源利用率得到了提升。

  • 降低管理線程的難度。多線程環(huán)境下對(duì)線程的管理是最容易出現(xiàn)問(wèn)題的,而線程池通過(guò)框架為我們降低了管理線程的難度。我們不用再去擔(dān)心何時(shí)該銷毀線程,如何最大限度的避免多線程的資源競(jìng)爭(zhēng)。這些事情線程池都幫我們代勞了。

  • 提升任務(wù)處理速度。線程池中長(zhǎng)期駐留了一定數(shù)量的活線程,當(dāng)任務(wù)需要執(zhí)行時(shí),我們不必先去創(chuàng)建線程,線程池會(huì)自己選擇利用現(xiàn)有的活線程來(lái)處理任務(wù)。

很顯然,線程池一個(gè)很顯著的特征就是“長(zhǎng)期駐留了一定數(shù)量的活線程”,避免了頻繁創(chuàng)建線程和銷毀線程的開(kāi)銷,那么它是如何做到的呢?我們知道一個(gè)線程只要執(zhí)行完了run()方法內(nèi)的代碼,這個(gè)線程的使命就完成了,等待它的就是銷毀。既然這是個(gè)“活線程”,自然是不能很快就銷毀的。為了搞清楚這個(gè)“活線程”是如何工作的,下面通過(guò)追蹤源碼來(lái)看看能不能解開(kāi)這個(gè)疑問(wèn)。

學(xué)習(xí)過(guò)線程池都知道,可以通過(guò)工廠類Executors來(lái)創(chuàng)個(gè)多種類型的線程池,部分類型如下:

public static ExecutorService newFixedThreadPool(int var0) {
        return new ThreadPoolExecutor(var0, var0, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
    }
    public static ExecutorService newSingleThreadExecutor() {
        return new Executors.FinalizableDelegatedExecutorService(new ThreadPoolExecutor(110L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()));
    }
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0214748364760L, TimeUnit.SECONDS, new SynchronousQueue());
    }
    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new Executors.DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1));
    }
    public static ScheduledExecutorService newScheduledThreadPool(int var0) {
        return new ScheduledThreadPoolExecutor(var0);
    }

無(wú)論哪種類型的線程池,最終都是直接或者間接通過(guò)ThreadPoolExecutor這個(gè)類來(lái)實(shí)現(xiàn)的。而ThreadPoolExecutor的有多個(gè)構(gòu)造方法,最終都是調(diào)用含有7個(gè)參數(shù)的構(gòu)造函數(shù)。

/**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters.
     *
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * @param unit the time unit for the {@code keepAliveTime} argument
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * @param threadFactory the factory to use when the executor
     *        creates a new thread
     * @param handler the handler to use when execution is blocked
     *        because the thread bounds and queue capacities are reached
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue}
     *         or {@code threadFactory} or {@code handler} is null
     */

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
 
{
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

① corePoolSize

顧名思義,其指代核心線程的數(shù)量。當(dāng)提交一個(gè)任務(wù)到線程池時(shí),線程池會(huì)創(chuàng)建一個(gè)核心線程來(lái)執(zhí)行任務(wù),即使其他空閑的核心線程能夠執(zhí)行新任務(wù)也會(huì)創(chuàng)建新的核心線程,而等到需要執(zhí)行的任務(wù)數(shù)大于線程池核心線程的數(shù)量時(shí)就不再創(chuàng)建,這里也可以理解為當(dāng)核心線程的數(shù)量等于線程池允許的核心線程最大數(shù)量的時(shí)候,如果有新任務(wù)來(lái),就不會(huì)創(chuàng)建新的核心線程。

如果你想要提前創(chuàng)建并啟動(dòng)所有的核心線程,可以調(diào)用線程池的prestartAllCoreThreads()方法。

② maximumPoolSize

顧名思義,其指代線程池允許創(chuàng)建的最大線程數(shù)。如果隊(duì)列滿了,并且已創(chuàng)建的線程數(shù)小于最大線程數(shù),則線程池會(huì)再創(chuàng)建新的線程執(zhí)行任務(wù)。所以只有隊(duì)列滿了的時(shí)候,這個(gè)參數(shù)才有意義。因此當(dāng)你使用了無(wú)界任務(wù)隊(duì)列的時(shí)候,這個(gè)參數(shù)就沒(méi)有效果了。

③ keepAliveTime


顧名思義,其指代線程活動(dòng)保持時(shí)間,即當(dāng)線程池的工作線程空閑后,保持存活的時(shí)間。所以,如果任務(wù)很多,并且每個(gè)任務(wù)執(zhí)行的時(shí)間比較短,可以調(diào)大時(shí)間,提高線程的利用率,不然線程剛執(zhí)行完一個(gè)任務(wù),還沒(méi)來(lái)得及處理下一個(gè)任務(wù),線程就被終止,而需要線程的時(shí)候又再次創(chuàng)建,剛創(chuàng)建完不久執(zhí)行任務(wù)后,沒(méi)多少時(shí)間又終止,會(huì)導(dǎo)致資源浪費(fèi)。


注意:這里指的是核心線程池以外的線程。還可以設(shè)置allowCoreThreadTimeout = true這樣就會(huì)讓核心線程池中的線程有了存活的時(shí)間。


④ TimeUnit

顧名思義,其指代線程活動(dòng)保持時(shí)間的單位:可選的單位有天(DAYS)、小時(shí)(HOURS)、分鐘(MINUTES)、毫秒(MILLISECONDS)、微秒(MICROSECONDS,千分之一毫秒)和納秒(NANOSECONDS,千分之一微秒)。

⑤ workQueue

顧名思義,其指代任務(wù)隊(duì)列:用來(lái)保存等待執(zhí)行任務(wù)的阻塞隊(duì)列。

⑥ threadFactory

顧名思義,其指代創(chuàng)建線程的工廠:可以通過(guò)線程工廠給每個(gè)創(chuàng)建出來(lái)的線程設(shè)置更加有意義的名字。

⑦ RejectedExecutionHandler

顧名思義,其指代拒絕執(zhí)行程序,可以理解為飽和策略:當(dāng)隊(duì)列和線程池都滿了,說(shuō)明線程池處于飽和狀態(tài),那么必須采取一種策略處理提交的新任務(wù)。這個(gè)策略默認(rèn)情況下是AbortPolicy,表示無(wú)法處理新任務(wù)時(shí)拋出異常。在JDK1.5中Java線程池框架提供了以下4種策略。


  • AbortPolicy:直接拋出異常RejectedExecutionException。
  • CallerRunsPolicy:只用調(diào)用者所在線程來(lái)運(yùn)行任務(wù),即由調(diào)用 execute方法的線程執(zhí)行該任務(wù)。
  • DiscardOldestPolicy:丟棄隊(duì)列里最近的一個(gè)任務(wù),并執(zhí)行當(dāng)前任務(wù)。
  • DiscardPolicy:不處理,丟棄掉,即丟棄且不拋出異常。

這7個(gè)參數(shù)共同決定了線程池執(zhí)行一個(gè)任務(wù)的策略:

當(dāng)一個(gè)任務(wù)被添加進(jìn)線程池時(shí):

  1. 線程數(shù)量未達(dá)到 corePoolSize,則新建一個(gè)線程(核心線程)執(zhí)行任務(wù)
  2. 線程數(shù)量達(dá)到了 corePools,則將任務(wù)移入隊(duì)列等待
  3. 隊(duì)列已滿,新建線程(非核心線程)執(zhí)行任務(wù)
  4. 隊(duì)列已滿,總線程數(shù)又達(dá)到了 maximumPoolSize,就會(huì)由上面那位星期天(RejectedExecutionHandler)拋出異常

說(shuō)白了就是先利用核心線程,核心線程用完,新來(lái)的就加入等待隊(duì)列,一旦隊(duì)列滿了,那么只能開(kāi)始非核心線程來(lái)執(zhí)行了。

上面的策略,會(huì)在閱讀代碼的時(shí)候體現(xiàn)出來(lái),并且在代碼中也能窺探出真正復(fù)用空閑線程的實(shí)現(xiàn)原理。

接下來(lái)我們就從線程池執(zhí)行任務(wù)的入口分析。

一個(gè)線程池可以接受任務(wù)類型有Runnable和Callable,分別對(duì)應(yīng)了execute和submit方法。目前我們只分析execute的執(zhí)行過(guò)程。

上源碼:

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */

        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) { //第一步:如果線程數(shù)量小于核心線程數(shù)
            if (addWorker(command, true))//則啟動(dòng)一個(gè)核心線程執(zhí)行任務(wù)
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {//第二步:當(dāng)前線程數(shù)量大于等于核心線程數(shù),加入任務(wù)隊(duì)列,成功的話會(huì)進(jìn)行二次檢查
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(nullfalse);//啟動(dòng)非核心線程執(zhí)行,注意這里任務(wù)是null,其實(shí)里面會(huì)去取任務(wù)隊(duì)列里的任務(wù)執(zhí)行
        }
        else if (!addWorker(command, false))//第三步:加入不了隊(duì)列(即隊(duì)列滿了),嘗試啟動(dòng)非核心線程
            reject(command);//如果啟動(dòng)不了非核心線程執(zhí)行,說(shuō)明到達(dá)了最大線程數(shù)量的限制,會(huì)使用第7個(gè)參數(shù)拋出異常
    }

代碼并不多,主要分三個(gè)步驟,其中有兩個(gè)靜態(tài)方法經(jīng)常被用到,主要用來(lái)判斷線程池的狀態(tài)和有效線程數(shù)量:

// 獲取運(yùn)行狀態(tài)
private static int runStateOf(int c)     return c & ~CAPACITY; }
// 獲取活動(dòng)線程數(shù)
private static int workerCountOf(int c)  return c & CAPACITY; }

總結(jié)一下,execute的執(zhí)行邏輯就是:

  • 如果 當(dāng)前活動(dòng)線程數(shù) < 指定的核心線程數(shù),則創(chuàng)建并啟動(dòng)一個(gè)線程來(lái)執(zhí)行新提交的任務(wù)(此時(shí)新建的線程相當(dāng)于核心線程);

  • 如果 當(dāng)前活動(dòng)線程數(shù) >= 指定的核心線程數(shù),且緩存隊(duì)列未滿,則將任務(wù)添加到緩存隊(duì)列中;

  • 如果 當(dāng)前活動(dòng)線程數(shù) >= 指定的核心線程數(shù),且緩存隊(duì)列已滿,則創(chuàng)建并啟動(dòng)一個(gè)線程來(lái)執(zhí)行新提交的任務(wù)(此時(shí)新建的線程相當(dāng)于非核心線程);

從代碼中我們也可以看出,即便當(dāng)前活動(dòng)的線程有空閑的,只要這個(gè)活動(dòng)的線程數(shù)量小于設(shè)定的核心線程數(shù),那么依舊會(huì)啟動(dòng)一個(gè)新線程來(lái)執(zhí)行任務(wù)。也就是說(shuō)不會(huì)去復(fù)用任何線程。在execute方法里面我們沒(méi)有看到線程復(fù)用的影子,那么我們繼續(xù)來(lái)看看addWorker方法。

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
 
            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;
 
            for (;;) {
                int wc = workerCountOf(c);
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }
        //前面都是線程池狀態(tài)的判斷,暫時(shí)不理會(huì),主要看下面兩個(gè)關(guān)鍵的地方
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask); // 新建一個(gè)Worker對(duì)象,這個(gè)對(duì)象包含了待執(zhí)行的任務(wù),并且新建一個(gè)線程
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());
 
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start(); // 啟動(dòng)剛創(chuàng)建的worker對(duì)象里面的thread執(zhí)行
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

方法雖然有點(diǎn)長(zhǎng),但是我們只考慮兩個(gè)關(guān)鍵的地方,先是創(chuàng)建一個(gè)worker對(duì)象,創(chuàng)建成功后,對(duì)線程池狀態(tài)判斷成功后,就去執(zhí)行該worker對(duì)象的thread的啟動(dòng)。也就是說(shuō)在這個(gè)方法里面啟動(dòng)了一個(gè)關(guān)聯(lián)到worker的線程,但是這個(gè)線程是如何執(zhí)行我們傳進(jìn)來(lái)的runnable任務(wù)的呢?接下來(lái)看看這個(gè)Worker對(duì)象到底做了什么。

private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    
{
        /**
         * This class will never be serialized, but we provide a
         * serialVersionUID to suppress a javac warning.
         */

        private static final long serialVersionUID = 6138294804551838833L;
 
        /** Thread this worker is running in.  Null if factory fails. */
        final Thread thread;
        /** Initial task to run.  Possibly null. */
        Runnable firstTask;
        /** Per-thread task counter */
        volatile long completedTasks;
 
        /**
         * Creates with given first task and thread from ThreadFactory.
         * @param firstTask the first task (null if none)
         */

        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }
 
        /** Delegates main run loop to outer runWorker. */
        public void run() {
            runWorker(this);
        }
 
        // Lock methods
        //
        // The value 0 represents the unlocked state.
        // The value 1 represents the locked state.
 
        protected boolean isHeldExclusively() {
            return getState() != 0;
        }
 
        protected boolean tryAcquire(int unused) {
            if (compareAndSetState(01)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }
 
        protected boolean tryRelease(int unused) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
 
        public void lock()        { acquire(1); }
        public boolean tryLock()  return tryAcquire(1); }
        public void unlock()      { release(1); }
        public boolean isLocked() return isHeldExclusively(); }
 
        void interruptIfStarted() {
            Thread t;
            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                }
            }
        }
    }

最重要的構(gòu)造方法:

Worker(Runnable firstTask) { // worker本身實(shí)現(xiàn)了Runnable接口
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask; // 持有外部傳進(jìn)來(lái)的runnable任務(wù)
            //創(chuàng)建了一個(gè)thread對(duì)象,并把自身這個(gè)runnable對(duì)象給了thread,一旦該thread執(zhí)行start方法,就會(huì)執(zhí)行worker的run方法
            this.thread = getThreadFactory().newThread(this); 
        }

在addWorker方法中執(zhí)行的t.start會(huì)去執(zhí)行worker的run方法:

public void run() {
   runWorker(this);
}

run方法又執(zhí)行了ThreadPoolExecutor的runWorker方法,把當(dāng)前worker對(duì)象傳入。

final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask; // 取出worker的runnable任務(wù)
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            // 循環(huán)不斷的判斷任務(wù)是否為空,當(dāng)?shù)谝粋€(gè)判斷為false的時(shí)候,即task為null,這個(gè)task啥時(shí)候?yàn)閚ull呢?
            // 要么w.firstTask為null,還記得我們?cè)趀xecute方法第二步的時(shí)候,執(zhí)行addWorker的時(shí)候傳進(jìn)來(lái)的runnable是null嗎?
            // 要么是執(zhí)行了一遍while循環(huán),在下面的finally中執(zhí)行了task=null;
            // 或者執(zhí)行第二個(gè)判斷,一旦不為空就會(huì)繼續(xù)執(zhí)行循環(huán)里的代碼。
            while (task != null || (task = getTask()) != null) {
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        task.run(); // 任務(wù)不為空,就會(huì)執(zhí)行任務(wù)的run方法,也就是runnable的run方法
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null// 執(zhí)行完成置null,繼續(xù)下一個(gè)循環(huán)
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

方法比較長(zhǎng),歸納起來(lái)就三步:

  1. 從worker中取出runnable(這個(gè)對(duì)象有可能是null,見(jiàn)注釋中的解釋);

  2. 進(jìn)入while循環(huán)判斷,判斷當(dāng)前worker中的runnable,或者通過(guò)getTask得到的runnable是否為空,不為空的情況下,就執(zhí)行run;

  3. 執(zhí)行完成把runnable任務(wù)置為null。

假如我們不考慮此方法里面的while循環(huán)的第二個(gè)判斷,在我們的線程開(kāi)啟的時(shí)候,順序執(zhí)行了runWorker方法后,當(dāng)前worker的run就執(zhí)行完成了。

既然執(zhí)行完了那么這個(gè)線程也就沒(méi)用了,只有等待虛擬機(jī)銷毀了。那么回顧一下我們的目標(biāo):Java線程池中的線程是如何被重復(fù)利用的?好像并沒(méi)有重復(fù)利用啊,新建一個(gè)線程,執(zhí)行一個(gè)任務(wù),然后就結(jié)束了,銷毀了。沒(méi)什么特別的啊,難道有什么地方漏掉了,被忽略了?

仔細(xì)回顧下該方法中的while循環(huán)的第二個(gè)判斷(task = getTask)!=null

玄機(jī)就在getTask方法中。

private Runnable getTask() {
        boolean timedOut = false// Did the last poll() time out?
 
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
 
            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }
 
            int wc = workerCountOf(c);
 
            // timed變量用于判斷是否需要進(jìn)行超時(shí)控制。
            // allowCoreThreadTimeOut默認(rèn)是false,也就是核心線程不允許進(jìn)行超時(shí);
            // wc > corePoolSize,表示當(dāng)前線程池中的線程數(shù)量大于核心線程數(shù)量;
            // 對(duì)于超過(guò)核心線程數(shù)量的這些線程或者允許核心線程進(jìn)行超時(shí)控制的時(shí)候,需要進(jìn)行超時(shí)控制
            // Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
 
            // 如果需要進(jìn)行超時(shí)控制,且上次從緩存隊(duì)列中獲取任務(wù)時(shí)發(fā)生了超時(shí)(timedOut開(kāi)始為false,后面的循環(huán)末尾超時(shí)時(shí)會(huì)置為true)
            // 或者當(dāng)前線程數(shù)量已經(jīng)超過(guò)了最大線程數(shù)量,那么嘗試將workerCount減1,即當(dāng)前活動(dòng)線程數(shù)減1,
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                // 如果減1成功,則返回null,這就意味著runWorker()方法中的while循環(huán)會(huì)被退出,其對(duì)應(yīng)的線程就要銷毀了,也就是線程池中少了一個(gè)線程了
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }
 
            try {
                // 注意workQueue中的poll()方法與take()方法的區(qū)別
                //poll方式取任務(wù)的特點(diǎn)是從緩存隊(duì)列中取任務(wù),最長(zhǎng)等待keepAliveTime的時(shí)長(zhǎng),取不到返回null
                //take方式取任務(wù)的特點(diǎn)是從緩存隊(duì)列中取任務(wù),若隊(duì)列為空,則進(jìn)入阻塞狀態(tài),直到能取出對(duì)象為止
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true// 能走到這里說(shuō)明已經(jīng)超時(shí)了
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

注釋已經(jīng)很清楚了,getTask的作用就是,在當(dāng)前線程中:

1,如果當(dāng)前線程池線程數(shù)量大于核心線程數(shù)量或者設(shè)置了對(duì)核心線程進(jìn)行超時(shí)控制的話(此時(shí)相當(dāng)于對(duì)所有線程進(jìn)行超時(shí)控制),就會(huì)去任務(wù)隊(duì)列獲取超時(shí)時(shí)間內(nèi)的任務(wù)(隊(duì)列的poll方法),獲取到的話就會(huì)繼續(xù)執(zhí)行任務(wù),也就是執(zhí)行runWorker方法中的while循環(huán)里的任務(wù)的run方法,執(zhí)行完成后,又繼續(xù)進(jìn)入getTask從任務(wù)隊(duì)列中獲取下一個(gè)任務(wù)。

如果在超時(shí)時(shí)間內(nèi)沒(méi)有獲取到任務(wù),就會(huì)走到getTask的倒數(shù)第三行,設(shè)置timeOut標(biāo)記為true,此時(shí)繼續(xù)進(jìn)入getTask的for循環(huán)中,由于超時(shí)了,那么就會(huì)進(jìn)入嘗試去去對(duì)線程數(shù)量-1操作,-1成功了,就直接返回一個(gè)null的任務(wù),這樣就回到了當(dāng)前線程執(zhí)行的runWorker方法中,該方法的while循環(huán)判斷getTask為空,直接退出循環(huán),這樣當(dāng)前線程就執(zhí)行完成了,意味著要被銷毀了,這樣自然就會(huì)被回收器擇時(shí)回收了。也就是線程池中少了一個(gè)線程了。因此只要線程池中的線程數(shù)大于核心線程數(shù)(或者核心線程也允許超時(shí))就會(huì)這樣一個(gè)一個(gè)地銷毀這些多余的線程。

2,如果當(dāng)前活動(dòng)線程數(shù)小于等于核心線程數(shù)(或者不允許核心線程超時(shí)),同樣也是去緩存隊(duì)列中取任務(wù),但當(dāng)緩存隊(duì)列中沒(méi)任務(wù)了,就會(huì)進(jìn)入阻塞狀態(tài)(隊(duì)列的take方法),直到能取出任務(wù)為止(也就是隊(duì)列中被新添加了任務(wù)時(shí)),因此這個(gè)線程是處于阻塞狀態(tài)的,并不會(huì)因?yàn)榫彺骊?duì)列中沒(méi)有任務(wù)了而被銷毀。這樣就保證了線程池有N個(gè)線程是活的,可以隨時(shí)處理任務(wù),從而達(dá)到重復(fù)利用的目的。

綜上所述,線程之所以能達(dá)到復(fù)用,就是在當(dāng)前線程執(zhí)行的runWorker方法中有個(gè)while循環(huán),while循環(huán)的第一個(gè)判斷條件是執(zhí)行當(dāng)前線程關(guān)聯(lián)的Worker對(duì)象中的任務(wù),執(zhí)行一輪后進(jìn)入while循環(huán)的第二個(gè)判斷條件getTask(),從任務(wù)隊(duì)列中取任務(wù),取這個(gè)任務(wù)的過(guò)程要么是一直阻塞的,要么是阻塞一定時(shí)間直到超時(shí)才結(jié)束的,超時(shí)到了的時(shí)候這個(gè)線程也就走到了生命的盡頭。

然而在我們開(kāi)始分析execute的時(shí)候,這個(gè)方法中的三個(gè)部分都會(huì)調(diào)用addWorker去執(zhí)行任務(wù),在addWorker方法中都會(huì)去新建一個(gè)線程來(lái)執(zhí)行任務(wù),這樣的話是不是每次execute都是去創(chuàng)建線程了?事實(shí)上,復(fù)用機(jī)制跟線程池的阻塞隊(duì)列有很大關(guān)系,我們可以看到,在execute在核心線程滿了,但是隊(duì)列不滿的時(shí)候會(huì)把任務(wù)加入到隊(duì)列中,一旦加入成功,之前被阻塞的線程就會(huì)被喚醒去執(zhí)行新的任務(wù),這樣就不會(huì)重新創(chuàng)建線程了。

我們用個(gè)例子來(lái)看下:

假設(shè)我們有這么一個(gè)ThreadPoolExecutor,核心線程數(shù)設(shè)置為5(不允許核心線程超時(shí)),最大線程數(shù)設(shè)置為10,超時(shí)時(shí)間為20s,線程隊(duì)列是LinkedBlockingDeque(相當(dāng)于是個(gè)無(wú)界隊(duì)列)。

當(dāng)我們給這個(gè)線程池陸續(xù)添加任務(wù),前5個(gè)任務(wù)執(zhí)行的時(shí)候,會(huì)執(zhí)行到我們之前分析的execute方法的第一步部分,會(huì)陸續(xù)創(chuàng)建5個(gè)線程做為核心線程執(zhí)行任務(wù),當(dāng)前線程里面的5個(gè)關(guān)聯(lián)的任務(wù)執(zhí)行完成后,會(huì)進(jìn)入各自的while循環(huán)的第二個(gè)判斷getTask中去取隊(duì)列中的任務(wù),假設(shè)當(dāng)前沒(méi)有新的任務(wù)過(guò)來(lái)也就是沒(méi)有執(zhí)行execute方法,那么這5個(gè)線程就會(huì)在workQueue.take()處一直阻塞的。這個(gè)時(shí)候,我們執(zhí)行execute加入一個(gè)任務(wù),即第6個(gè)任務(wù),這個(gè)時(shí)候會(huì)進(jìn)入execute的第二部分,將任務(wù)加入到隊(duì)列中,一旦加入隊(duì)列,之前阻塞的5個(gè)線程其中一個(gè)就會(huì)被喚醒取出新加入的任務(wù)執(zhí)行了。(這里有個(gè)execute的第二部分的后半段執(zhí)行重復(fù)校驗(yàn)的代碼即addWorker(傳入null任務(wù)),目前還沒(méi)搞明白是怎么回事)。

在我們這個(gè)例子中,由于隊(duì)列是無(wú)界的,所以始終不會(huì)執(zhí)行到execute的第三部分即啟動(dòng)非核心線程,假如我們?cè)O(shè)置隊(duì)列為有界的,那么必然就會(huì)執(zhí)行到這里了。

小結(jié)

通過(guò)以上的分析,應(yīng)該算是比較清楚地解答了“線程池中的核心線程是如何被重復(fù)利用的”這個(gè)問(wèn)題,同時(shí)也對(duì)線程池的實(shí)現(xiàn)機(jī)制有了更進(jìn)一步的理解:

當(dāng)有新任務(wù)來(lái)的時(shí)候,先看看當(dāng)前的線程數(shù)有沒(méi)有超過(guò)核心線程數(shù),如果沒(méi)超過(guò)就直接新建一個(gè)線程來(lái)執(zhí)行新的任務(wù),如果超過(guò)了就看看緩存隊(duì)列有沒(méi)有滿,沒(méi)滿就將新任務(wù)放進(jìn)緩存隊(duì)列中,滿了就新建一個(gè)線程來(lái)執(zhí)行新的任務(wù),如果線程池中的線程數(shù)已經(jīng)達(dá)到了指定的最大線程數(shù)了,那就根據(jù)相應(yīng)的策略拒絕任務(wù)。

當(dāng)緩存隊(duì)列中的任務(wù)都執(zhí)行完了的時(shí)候,線程池中的線程數(shù)如果大于核心線程數(shù),就銷毀多出來(lái)的線程,直到線程池中的線程數(shù)等于核心線程數(shù)。此時(shí)這些線程就不會(huì)被銷毀了,它們一直處于阻塞狀態(tài),等待新的任務(wù)到來(lái)。

注意: 本文所說(shuō)的“核心線程”、“非核心線程”是一個(gè)虛擬的概念,是為了方便描述而虛擬出來(lái)的概念,在代碼中并沒(méi)有哪個(gè)線程被標(biāo)記為“核心線程”或“非核心線程”,所有線程都是一樣的,只是當(dāng)線程池中的線程多于指定的核心線程數(shù)量時(shí),會(huì)將多出來(lái)的線程銷毀掉,池中只保留指定個(gè)數(shù)的線程。那些被銷毀的線程是隨機(jī)的,可能是第一個(gè)創(chuàng)建的線程,也可能是最后一個(gè)創(chuàng)建的線程,或其它時(shí)候創(chuàng)建的線程。一開(kāi)始我以為會(huì)有一些線程被標(biāo)記為“核心線程”,而其它的則是“非核心線程”,在銷毀多余線程的時(shí)候只銷毀那些“非核心線程”,而“核心線程”不被銷毀。這種理解是錯(cuò)誤的。

來(lái)源blog.csdn.net/anhenzhufeng/article/details/88870374

版權(quán)申明:內(nèi)容來(lái)源網(wǎng)絡(luò),版權(quán)歸原創(chuàng)者所有。除非無(wú)法確認(rèn),我們都會(huì)標(biāo)明作者及出處,如有侵權(quán)煩請(qǐng)告知,我們會(huì)立即刪除并表示歉意。謝謝!





感謝閱讀



瀏覽 44
點(diǎn)贊
評(píng)論
收藏
分享

手機(jī)掃一掃分享

分享
舉報(bào)
評(píng)論
圖片
表情
推薦
點(diǎn)贊
評(píng)論
收藏
分享

手機(jī)掃一掃分享

分享
舉報(bào)

感谢您访问我们的网站,您可能还对以下资源感兴趣:

国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频 白丝在线观看| 三级中文无码| 婷婷五月亚洲精品AAA片在| 日韩一级在线| 久久久久久成人电影| 91小视频在线| 亚洲日韩黄色| 很很撸在线视频| 亚洲高清无码视频| 青草视频在线播放| 久久久久无码| 中文字幕日韩成人| 国产秘精品区二区三区日本| 牛牛精品一区二区AV| 操逼在线观看| 日本黄色三级视频| 国产一级婬片A片免费无成人黑豆 国产真实露脸乱子伦对白高清视频 | 97超碰在线视| A片观看视频| 欧美精产国品一二三产品在哪买 | 久久yy| 日韩人妻精品无码久久边| 99热99| 国产操比视频| 日本大香蕉伊人| 日韩熟妇无码| 无码欧美精品一区二区| 免费黄色大片网站| 亚洲无码视频在线观看| 国产乱妇无码毛片A片在线看下载 日韩电影免费在线观看中文字幕 欧美性爱中文字幕 | 国产天堂av| 国产一级影院| 一区二区三区四区视频| 1024在线视频| 成人av免费在线观看| 国产在线视频一区二区三区| 怡红院成人av| 狼友视频免费在线观看| 日韩性爱网址| 日韩高清色| 伊人大香蕉视频| 99色视频| 加勒比在线| 精品国产欧美一区二区三区成人| 欧美一级AA大片免费看视频| 天天拍天天射| 香蕉视频啪啪啪| 久操香蕉| 蜜桃久久久久久久| 国产欧美精品成人在线观看| 波多野结衣不卡| 国产精品成人午夜福利| 噜噜噜av| 四虎av在线| 国产精品AV在线观看| 免费黄色片子| 在线观看亚洲中文字幕| 国产精品无| 黄片视频链接| 免费无码在线看| 九九热精品| 韩国午夜福利| 人妻精品一区二区三区| 岛国A片| 男人天堂手机在线| 影音av资源| 大香蕉午夜视频| 亚洲成人一二三区| 亚洲无码久久网| 精品九九九九九九| 佐山爱人妻无码蜜桃| 殴美色色网| 黄色视频日本| 久久久999精品日韩一区二区| 欧美人与禽乱婬A片| 日韩一级在线播放| 免费无人区一码二码乱码怎么办| 午夜精品久久久| 激情视频免费在线观看| 少妇厨房愉情理伦BD在线观看| 99久久99久久兔费精桃| 97人人爽人人爽人人爽人人爽| 蝌蚪窝在线视频观看| 亚洲色男人天堂| 免费观看高清无码视频| 热无码av| 中文字幕乱码亚洲无线码按摩| 92午夜福利天堂视频2019| 欧美成人毛片AAAAAA| 天堂中文在线观看| 免费黄片在线看| 亚洲无码三区| 国产一区在线视频| 麻豆av无码| 亚洲在线视频播放| 国产传媒视频| www.国产在线观看| 久久久久久成人电影| 午夜精品久久久久久久| 午夜在线观看视频18| 日韩艹| 麻豆成人无码精品视频| 成人AV中文解说水果派| 四虎精品一区二区| 黄色AV免费看| 中文字幕在线精品| eeuss一区| 成人网| 成人自拍视频在线观看| 日本黄色大片| 熟妇人妻中文字幕无码老熟妇| 黄网免费在线观看| 97人人妻| 蜜臀久久99精品久久久老牛影视| 操逼在线视频| 樱桃码一区二区三区| 免费在线观看黄| 日韩黄色一级片| 日韩性爱在线| 撸一撸成人在线做爱视频。| 伊人久久狼人| 久久久国产精品人人片| 呦呦av| 苍井空在线播放| 国产成人精品国内自产拍免费看 | 国产黄色视频免费观看| 俺来俺去| 亚洲无码免费观看视频| 国产激情AV| 欧美综合网| 久色视频福利| 欧美一区二区三区激情| 秋霞亚洲| 精品交换一区二区三区无码| 丁香六月婷| 丁香婷婷社区| 18禁网站免费观看| 青青操b| 亚洲男女免费视频| 中文字幕黄色片| av青青草原| 黄页网址在线观看| 91亚洲精品乱码久久久久久蜜桃| 北条麻妃无码精品AV| 大鸡巴久久久| 欧美77777| 日韩无码视频一区| 国产婷婷久久Av免费高清| 99艹艹| 欧美喷水视频| 51国产视频| 日本黄色a片| chinese搡老熟老妇人| 伊人综合大香蕉| 亚洲av毛片| 国产在线拍偷自揄拍无码一区二区 | 性欧美丰满熟妇XXXX性久久久| 草久av| 国产主播专区| 狠狠狠狠狠狠狠狠| 性天堂| 日韩三级在线观看| 操b在线观看| 偷拍99| 91视频美女模特| 开心激情播播网| 人人操人人干人人妻| 在线国产激情视频| av无码精品一区| 日本中文在线观看| 亚洲456| 波多野结衣无码AV在线| 婷婷丁香六月| 91麻豆福利在线观看| 国产人妻精品一区二区三区不卡| www.蜜桃av| 69国产成人综合久久精品欧美 | 色婷婷黄色| 欧美成人一级a片| 国产美女自拍| 91蜜桃传媒在线观看| 日本无码在线视频| 久久艹视频| 一区二区AV| 92午夜福利天堂视频2019| 国产高清在线免费观看AV片| 国产美女自拍| 亚洲AV成人无码精品| 日本特黄AA片免费视频| 国产中文字幕在线视频| 四虎操逼| 男女黄网站| 国产在线高潮| 国产乱码一区二区三区四区在线 | 内射免费看| 亚洲天堂在线播放| 猫咪亚洲AV成人无码电影| 成人你懂的| 日本V片| 青青青草视频在线观看| 成人国产在线| 成人在线乱码视频| 最美人妖系列国产Ts涵涵| 亚洲成人资源| 亚洲精品中文字幕乱码三区91| 骚婷婷| 农村A片婬片AAA毛片| 欧美日韩性爰视频| 无码中文字| 2025最新国产成人精品| 久久久精品亚洲| 蜜桃av秘无码一区二区| 亚洲精品一区无码A片丁香花| 欧美18禁| 香蕉操逼| 在线免费观看中文字幕| 中文字幕综合| 狠狠躁日日躁夜夜躁A片视频| A级黄色毛片| 国产乱子伦-区二区三区熟睡91 | 91欧美日韩| 日韩aaa视频| 中文字幕精品一级A片| 一级特黄录像免费播放下载软件| 色婷婷视频在线播放| 中文无码av| 一级性生活视频| 艹美女视频| 日日摸日日操| 国产美女自慰网站| 日本最新免费二区| 91国内产香蕉| 俺去俺来也WWW色老板| 99免费在线观看| 狠狠干高清成人二区三区| 婷婷色色五月| 91三级在线观看| 先锋影音AV资源网| 少妇人妻偷人精品无码视频新浪| 五月丁香婷中文字幕| 国产骚女| 中文字幕一区二区三区四虎在线| 香蕉婷婷亚洲丁香| 特爽特黄特级特色视频| 大香蕉欧美在线| 99久久精品国产一区色| 欧美欧美欧美| 日韩在线91| 欧美一级精品| 水果派AV解说| 亚洲天堂AV2025| 日韩无码免费电影| 91啪啪视频| 成人在线乱码视频| 日韩欧美高清无码| 国产V视频| 亚洲日韩精品中文字幕在线| 西西444WWW无码视频软件| 996re| 五月天色综合| 黄色天堂天天看| 亚洲热在线视频| 五月丁香性爱| 91性爱| 91麻豆电影| A片黄色电影网站| 青青草原网| 四虎av在线播放| 日本在线一区| 精品人妻一区二区三区-国产精品 无码人妻av黄色一区二区三区 | 丁香五月婷婷视频| 久久婷五月天| 午夜国产在线观看| 天天干网址| 天天日比| 欧美日韩在线视频免费观看| 亚洲日韩欧美色图| 在线免费观看无码视频| 在线一级片| 人妻人人妻| 高清无码专区| 三级片久久久| 亚洲天堂福利| 中文字幕av第一页| 亚洲综合色网| 操碰99| 久久久一| 日韩免费AV| 日本中文不卡| 波多野成人无码精品视频| 午夜性爽视频男人的天堂| 精品一区二区免费| 免费黄片网站在线观看| 青青三级片| 国产剧情一区二区三区| 欧日无码| 亚洲AV无码成人精品久久久| 影音av资源| 水蜜桃一区二区| 黑种人配中国少妇HD| 亚洲国产爱| 亚洲免费网站| 嫩草导航| 人人人人操| 97中文在线| 国产精品久久久999| 中文无码av| 亚洲国产一| 无码不卡在线观看| 欧美成人网站视频| 无码国产高清| 中文字幕AV在线播放| 日韩中文字幕视频在线| 中文在线高清字幕| 亚洲国产另类精品| 亚洲免费成人网| 一级A片在线观看| 艹在线观看| 国产在线观看无码免费视频| 影音先锋中文字幕资源| 欧美日韩一区视频| 91人妻无码精品一区二区毛片| 日韩中文字幕一区二区| 中文字幕免费在线播放| 日本成人中文字幕在线观看| 91久久人澡人妻人人做人人爽97| 欧美视频在线播放| 人妻国产| 韩国无码一区二区三区| 水蜜桃视频网站在线观看| 国产精品porn| 亚洲成人影片| 国产精品一色哟哟哟| 亚洲小视频在线观看| 偷拍内射| 亚洲精品国产成人综合久久久久久久久| 在线观看高清无码中文字幕| 俺来俺也去www色在线观看| 91欧美日韩| 色视频免费在线观看| 2014天堂网| 久久久午夜| 国产乱子伦视频国产印度| 久久久久久久久久免费视频| 东京热黄色| 亚洲福利视频97| 婷婷五月国产| 五月丁香在线观看| 色哟哟无码精品一区二区三区| 欧美三级片网址| 亚洲综合网在线观看| 西西444WWW无码大胆| 欧美成人一级a片| 亚洲成人三级| 色丁香六月| 蜜桃av无码一区二区三区| 亚洲污网| 天堂俺去俺来也www久久婷婷| ⅴA日本成人| 日韩久久网站| 久久久久久久人妻丝袜| 国产精品V亚洲精品V日韩精品| 超碰超碰| 肏逼综合网| 波多野结衣视频网站| 91三级片网站| 蜜桃视频一区| 丁香六月婷婷综合激情欧美| 欧美性爱小说| 亚洲精品国产精品国自产| 在线观看黄色视频网站| av网站在线播放| 久久av电影| 亚洲娱乐在线| 欧美精品久久久久久久多人混战| 青青草免费在线观看| 大香蕉超碰| AV日日| 国产黄色免费| 亚洲AV无码成人精品区在线欢看| 2025精品偷拍视频| 黄色一级片免费观看| 18禁黄网站| 肏屄视频在线播放| 亚洲一区二区黄色电影视频网站 | 91亚洲精品久久久久蜜桃| 91国内偷拍| 在线中文字幕777| 91在线综合| 密臀福利导航| 一区二区视频在线| 九九伊人大香蕉| 天天添天天干| 超碰碰97| 久久蜜桃| 欧美性猛交XXXX乱大交HD| 逼特逼| 亚州天堂网| 大帝AV| 中文字幕免费在线播放| 山东乱子伦视频国产| 一本一道久久| 国产日韩欧美91| 亚洲性爱在线观看| 午夜福利电影网| 丰臀肥逼高清视频电影播放| 五月丁香狠狠爱| www.日韩系列| 伊人88| 国产成人久久777777| 色色五月婷婷| 亚洲男同Gay一区二区| 操逼一区| 中国一级黄色毛片| 在线播放日韩| 无码乱伦视频| 88av在线播放| 在线小视频| 黄色视频网站在线看| 日韩中字无码黄片| 色六月婷婷| 久久久久久久久久久久成人| 久久er热| 91人妻无码精品一区二区三区| 手机看片午夜福利网| 精品久久久国产| 久久久久久久久久久亚洲| 韩国精品一区二区| 日韩一区二区三区无码电影| 丁香五月婷婷五月| 免费无码av| 一区二区精品视频| 做爱网站免费| 国产网站精品| 亚洲精品乱码久久久久久按摩观| 精品免费在线观看| 天天视频亚洲| 麻豆91视频| 天天日,天天干,天天操| 岛国A视频| 玖玖爱国产| 精品一区二区免费| 黄片网址| 成人无码交配视频国产网站| 青青草视频免费观看| 成人在线观看网站| 四虎成人精品在永久免费| 性爱AV| 高清视频一区二区| 蜜臀网| 国产剧情一区二区av在线观看| 男人的天堂视频网站| 欧美老妇另类BBwBBw| 亚洲无码在线免费观看| 国产精品国产三级国产AⅤ原创 | 亚洲AV成人无码精品| 国产三级AV在线观看| 亚洲成人天堂| 欧美在线视频网| 人妻中文字幕网| 久久91欧美特黄A片| 有码视频在线观看| www一个人免费观看视频www| 亚洲欧美成人视频| 无码字幕| 亚洲有码在线| 大香蕉com| 大黑逼网| 国产一级a毛一级a毛视频在线网站 | 日韩婷婷| 久久久久久久无码| 四虎最新地址| 欧美成人毛片AAAAAA| 澳门免费毛片| AV资源在线免费观看| 欧美亚洲综合手机在线| 久久亚洲av| 欧美日韩第一区| 成人三级电影网| 欧美黑吊大战白妞欧美大片| 中文字幕精品视频在线观看| 北条麻妃精品青青久久价格| 91久久久无码国产一区二区三区| 日韩WWW| 精品成人Av一区二区三区| 内射少妇18| 艹逼免费视频| 欧美日韩美女| 人人操人人| 人人肏人人摸| 在线观看视频国产| 亚洲vs无码蜜桃少妇| 国产高清无码视频在线观看| 天天拍夜夜拍| 青草久久久久| 日日夜夜爽歪歪| 亚洲无aV在线中文字幕| 一级a看片在线观看| 巨乳一区二区三区| 欲色AV| 中文字幕Av在线| 亚洲天堂在线视频播放| 欧美大香蕉伊人网| 人人看人人射| 天天射天天射| 经典三级在线视频| 日本四级片| 91工厂露脸熟女| 京熱大亂交无碼大亂交| 人人操人人妻人人看| 约操少妇| 国产黄页| 亚洲成人内射| av一区二区在线观看| 男人av网站| 先锋影音av在线| 欧美色噜噜| 欧美精品久久久久久久久| 肥臀AV在线| 欧美日韩性爱视频| 97爱爱爱| 蜜芽成人精品久久久视频| 婷婷国产成人精品| 午夜无码电影| 欧美中文日韩| 精品国产毛片| 亚洲一区无码在线观看| 丁香六月婷婷| 成人视频一区二区三区| 俺去也在线视频| PORNY九色视频9l自拍| 中文字字幕中文字幕乱码| 天堂中文在线视频| 最新日韩无码| 国內精品久久久久久久| 日韩激情视频在线观看| 亚洲在线| 日本不卡一区二区三区| 国产小视频在线播放| 91热爆在线| 中文字幕精品综合| 一区二区三区精品| 操屄视频在线观看| 中文字幕亚洲高清| 成人伊人综合网| 伊人网视频在线播放| 久久久久久久久久国产精品免费观看-百度 | 亚洲在线成人| 国产又粗又大又黄视频| 日本成人视频在线免费播放| 水果派av解说| 色综合综合色| 日韩一区二区不卡| 日韩在线99| 青草青青视频| 日韩群交| 黄片免费看| 国产成人视频免费观看| 亚洲自拍小说| 在线观看三级| 我要操视频| 日韩精品欧美一区二区三区| 天天色天天干天天日| 天天日夜夜添| 日韩av高清| 国产成人一区二区无码| 欧美色图网址| 美妇肥臀一区二区三区-久久99精品国| 亚洲日韩国产AV无码无码精品| 麻豆亚洲AV成人无码久久精品| 久久久久久久久久国产精品| 小黄片免费看| 亚洲欧洲免费看| 色色天堂成人电影| 欧美性爱中文字幕| 黄色A视频| 久久精品91| 亚洲无码久久精品| 亚洲不卡一区二区三区| 免费性网| 日本乱伦电影中文字幕| 人人干人人爱| 91大鸡巴| 欧美午夜精品成人片在线播放| 97AV人妻无码视频二区| 熟女高潮| 国产suv精品一区二区6精华液 | 另类老妇极品BBWBBw| 91艹艹| 日韩三级在线免费观看| 成人福利视频| 精品欧美一区二区三区| A片小视频| 久久艹国产| 91成人在线播放| 四川BBB嫩BBBB爽BBBB| 欧美精品久久久久久久久| 久久思热国产| 91国产精品视频在线| 久久无码电影| 亚洲激情网站| 亚洲午夜福利电影| 国产黄色免费观看| 精品国产成人a在线观看| 中文字幕乱码中文乱码91| 91色在线视频| 高清在线无码视频| 久久久精品999| 影音先锋无码AV| 色欲影视插综合一区二区三区| 午夜精品秘一区二区三区| 黄页网站免费在线观看| 91精品视频网站| 一级黄色视频免费看| 婷婷精品在线视频| 好吊顶亚洲AV大香蕉色色| 超碰欧美在线| 一区二区三区福利| 午夜视频无码| 欧美性爱日韩| 北条麻纪视频| 国产V精品| 欧洲尤物不卡播放六区| 欧美一区二区三区在线| 天天综合色| 色五月婷婷中文字幕| 97国产精品视频| 999免费视频| 亚洲日本高清| 一级片成人| 福利网址| 少妇4p| 精品久久免费视频| 大香蕉com| 久久九一| 白天操夜夜操| 91精品视频在线免费观看| av天堂小说网| 91香蕉在线看| 亚洲在线无码播放| 色噜噜在线观看| 日无码在线| 男女怕怕网站| 婷婷久草网| 操骚B| 国产激情免费| 一级做a爰片毛片A片| 四虎最新视频| 夜夜爱爱| 蜜挑视频一区二区三区| 中文字幕亚洲精品| 大香蕉欧美| 久久久一区二区| 亚洲成人黄色| 91嫩草欧美久久久九九九| 91精品久久久久久久| 国内精品无码| 日日干天天干| 亚洲最大成人网站| 五月激情视频| 欧洲精品在线观看| 欧美久久久| 婷婷色导航| 国产激情在线视频| 大香蕉伊人在线视频| 成人区精品一区二区婷婷| 91人妻无码视频| 国内操逼视频| 水蜜桃一区二区| 五月丁香综合| 国产精品视频| 尻屄视频| 插进去综合图| 99热精品免费在线观看| 欧美亚洲色色网视频| 3级片网站| 人妻无码一区二区三区免费| 亚洲成人网站视频| 污污污污污www网站免费民国| 亚洲AV无码一区毛片AV| 在线看片国产| 精品无码一区二区三区四区五区| 亚洲码AV波多野| 噼里啪啦免费观看视频大全| 亚洲三级视频在线播出| 国内自拍欧美| 亚洲天堂在线视频播放| 人妻在线免费视频| 国产精品天天狠天天看| 偷拍-91爱爱| 色婷婷国产精品| 欧美日逼网| 日韩中文字幕免费| 91九色91蝌蚪91窝成人| 色哟哟国产| 特级西西444www高清| 欧美黄色免费看| 日韩天天干| 日韩中文字幕无码| 成人AV电影在线观看| 欧美精品毛片| 亚洲成人动漫在线| 艹在线观看| 欧美污视频在线观看| 在线亚洲一区| 五月天婷婷丁香网| 天天干天| 黄色视频网站国产| 五十路无码| 97人妻在线| 高清无码毛片| 性99网站| 中字无码av| 婷婷V亚洲V丁香月天V日韩V| 精品人妻一区二区三区蜜桃| www伊人| 亚州在线中文字幕经典a| 安微妇搡BBBB搡BBBB| 麻豆视频一区| 成人日韩欧美| 国产午夜视频在线观看| 中文字幕精品无码亚| 搞黄免费视频视频| 黄色在线网| 北条麻妃无码视频在线| 88av在线播放| 国产97在线视频| 开心色情| 色情电影网站| 精品国产乱码久久久久久郑州公司 | 成人做爰100片免费视频| 操B视频免费看| 五月琪琪| 国产小电影在线| 三级三级久久三级久久18| 亚洲无码综合| 国产日逼视频| 丁香婷婷久久久综合精品国产| 国产91麻豆视频| 3D动漫操逼视频| 国产性爱自拍视频| 三区在线| 久久激情视频| 91精品国产乱码久久久竹菊| 开心四房播播第四婷婷| 亚洲vs无码蜜桃少妇| 欧美日韩无| 国产精彩无码视频| 中文字幕在线国产| 欧美亚洲性爱| 日本免费爱爱视频| 中文字幕不卡AV在线观看| 亚洲日本一区二区三区| 欧美成人手机在线观看| 伊人在线视频观看| 欧美成人午夜福利| 2014天堂网| sesese| 中文字幕永久在线视频v1.0| 夜夜撸一撸| 欧美区亚洲区| 狠狠综合网| 日韩无码一二三| 最新中文字幕| 国产精品欧美综合亚洲| 操屄视频免费观看| 色色五月丁香婷婷| 国产原创精品| 国产一区二区AV| 国产无套进入免费| 成人伊人AV| 懂色av懂色av粉嫩av| 国产成人精品一区二| 欧美日韩精品一区二区| 婷婷综合视频| 国产喷水ThePorn| 玖玖国产精品| 国产一区在线看| 在线观看免费A片| 91丨九色丨东北熟女| 玩弄大乳乳妾高潮乳喷视频| 自拍偷拍福利视频网站| 亚洲AV成人电影| www.婷婷六月天| 四虎性爱| 色操人 | 久久久久久久香蕉视频| 不卡无码免费视频| 秋霞一区二区| 国产成人va| 青草久久久| 成人伦理聚合| 亚洲欧美在线视频免费| 不卡的一区二区| 成人网| 久久久久久久人妻丝袜| 西西444WWW无码大胆在线观看| 伊人逼逼| 黄色视频免费播放| 一级免费黄色片| 奶大丰满一乱一视频一区二区三区在 | 国产女人精品视频| 探花一区二区| 国产熟女| 国产精品久久久精品| 亚洲免费精品视频| 亚洲三级视频在线播出| 影音先锋麻豆| 日韩无码首页| 亚洲中文字幕在线观看视频| 欧美日韩视频免费观看| 国产精彩无码视频| 日韩肏屄视频| 强开小嫩苞一区二区三区视频| 刘玥精品A片在线观看| 超碰在线天天| 在线免费看a片| AV在线天堂| 中文字幕免费中文| 婷婷五月天丁香网| 青青超碰| 国产黄色av| 成年人AV| 97超碰伊人| 淫揉BBB揉揉揉BBBBB| aaa在线免费视频| 91二区三区| 91精品国产aⅴ一区二区| 99热最新网址| 人妻少妇中文字幕久久牛牛| 天堂在线9| AV免费在线播放| 91成人在线视频| AV观看免费| 91一级特黄大片| 淫揉BBB揉揉揉BBBBB| 人人看人人搞人人摸| 亚洲日韩字幕| 欧洲成人在线视频| 成人超碰在线| 91艹艹| 色综合久久久无码中文字幕999| 成人国产在线观看| 免费看AV大片| 亚洲熟妇AV日韩熟妇在线| 成人激情视频网| 日韩二区| 少妇搡BBBB搡BBB搡造水多, | 国产中文字幕波多| 97在线观看免费| 特级丰满少妇免费观看| 日韩欧美高清在线| 一本一道伊人99久久综| 99久久精品国产色欲| 欧美日韩免费观看视频| 91三级电影| 国产无遮挡又黄又爽免费网站| 亚洲日韩一区二区三区四区| 97精品一区二区三区A片| 99视频精品在线| 天天干天天操综合| 日本精品在线播放| 欧美日韩在线一区| 欧美午夜精品一区二区蜜桃| 成人网站AV| 北条麻妃无码播放| 久久久久久久久久国产精品免费观看-百度 | 91麻豆精品国产91久久久久久| 国产肏逼视频| 亚洲性夜夜天天天天天天| 国产熟睡乱子伦午夜视频_第1集| 免费无码进口视频| 黄色大片久草| 欧美69影院| 在线免费A片| 成人视频91| 欧美BBWBBWBBWBBWBBwBBW | 无码迷穴| 中文在线A∨在线| 一区二区三区成人电影| 日韩无任何视频在线观看| 成人黄网站免费视频| 亚洲欧美视频在线| 欧美综合网在线观看| 欧美草逼网| 中文字幕第98页| 中文字幕日韩无码片| 欧美国产一区二区| 蜜桃视频无码| 久热在线资源福利站| 国产在线视频91| 伊人网址| 2020无码| 爆草美女| 欧美亚洲色色网视频| 欧美熟妇一区二区三区| 亚洲中文无码字幕| 91国产视频网站| 欧美激情在线观看| 91在线无码精品秘国产三年 |