1. 程式人生 > >【Java】執行緒池ThreadPoolExecutor實現原理

【Java】執行緒池ThreadPoolExecutor實現原理

引言

執行緒池:可以理解為緩衝區,由於頻繁的建立銷燬執行緒會帶來一定的成本,可以預先建立但不立即銷燬,以共享方式為別人提供服務,一來可以提供效率,再者可以控制執行緒無線擴張。合理利用執行緒池能夠帶來三個好處:

  1. 降低資源消耗。通過重複利用已建立的執行緒降低執行緒建立和銷燬造成的消耗。
  2. 提高響應速度。當任務到達時,任務可以不需要等到執行緒建立就能立即執行。
  3. 提高執行緒的可管理性。執行緒是稀缺資源,如果無限制的建立,不僅會消耗系統資源,還會降低系統的穩定性,使用執行緒池可以進行統一的分配,調優和監控。

但是要做到合理的利用執行緒池,必須對其原理了如指掌。

執行緒的幾種狀態

執行緒在一定條件下,狀態會發生變化。根據執行緒的幾種狀態這篇文章,執行緒一共有以下幾種狀態:

1、新建狀態(New):新建立了一個執行緒物件。
2、就緒狀態(Runnable):執行緒物件建立後,其他執行緒呼叫了該物件的start()方法。該狀態的執行緒位於“可執行執行緒池”中,變得可執行,只等待獲取CPU的使用權,即在就緒狀態的執行緒除CPU之外,其它的執行所需資源都已全部獲得。
3、執行狀態(Running):就緒狀態的執行緒獲取了CPU,執行程式程式碼。
4、阻塞狀態(Blocked):阻塞狀態是執行緒因為某種原因放棄CPU使用權,暫時停止執行。直到執行緒進入就緒狀態,才有機會轉到執行狀態。阻塞的情況分三種:

  • ①. 等待阻塞:執行的執行緒執行wait()方法,該執行緒會釋放佔用的所有資源,JVM會把該執行緒放入“等待池”中。進入這個狀態後,是不能自動喚醒的必須依靠其他執行緒呼叫notify()notifyAll()方法才能被喚醒。
  • ②. 同步阻塞:執行的執行緒在獲取物件的同步鎖時,若該同步鎖被別的執行緒佔用,則JVM會把該執行緒放入“鎖池”中。
  • ③. 其他阻塞:執行的執行緒執行sleep()join()方法,或者發出了I/O請求時,JVM會把該執行緒置為阻塞狀態。當sleep()狀態超時、join()等待執行緒終止或者超時,或者I/O處理完畢時,執行緒重新轉入就緒狀態。

5、死亡狀態(Dead):執行緒執行完了或者因異常退出了run()方法,該執行緒結束生命週期。

執行緒變化的狀態轉換圖如下:

執行緒狀態轉換圖

拿到物件的鎖標記,即為獲得了對該物件(臨界區)的使用許可權。即該執行緒獲得了執行所需的資源,進入“就緒狀態”,只需獲得CPU,就可以執行。

因為當呼叫wait()後,執行緒會釋放掉它所佔有的“鎖標誌”,所以執行緒只有在此獲取資源才能進入就緒狀態。

下面作下解釋:

  • 執行緒的實現有兩種方式,一是繼承Thread類,二是實現Runnable介面,但不管怎樣, 當我們new了這個物件後,執行緒就進入了初始狀態;
  • 當該物件呼叫了start()方法,就進入就緒狀態;
  • 進入就緒後,當該物件被作業系統選中,獲得CPU時間片就會進入執行狀態;
  • 進入執行狀態後情況就比較複雜;
    1. run()方法或start()方法結束後,執行緒就進入終止狀態;
    2. 當執行緒呼叫了自身的sleep()方法或其他執行緒的join()方法,程序讓出CPU,然後就會進入阻塞狀態(該狀態既停止當前執行緒,但並不釋放所佔有的資源,即呼叫sleep()函式後,執行緒不會釋放它的“鎖標誌”。)。當sleep()結束或join()結束後,該執行緒進入可執行狀態,繼續等待OS分配CPU時間片;典型地,sleep()被用在等待某個資源就緒的情形;測試發現條件不滿足後,讓執行緒阻塞一段時間後重新測試,直到條件滿足為止。
    3. 執行緒呼叫了yield()方法,意思是放棄當前獲得的CPU時間片,回到就緒狀態,這時與其他程序處於同等競爭狀態,OS有可能會接著又讓這個程序進入執行狀態;呼叫yield() 的效果等價於排程程式認為該執行緒已執行了足夠的時間片從而需要轉到另一個執行緒。yield()只是使當前執行緒重新回到可執行狀態,所以執行yield()的執行緒有可能在進入到可執行狀態後馬上又被執行。
    4. 當執行緒剛進入可執行狀態(注意,還沒執行),發現將要呼叫的資源被synchronized(同步),獲取不到鎖標記,將會立即進入鎖池狀態,等待獲取鎖標記(這時的鎖池裡也許已經有了其他執行緒在等待獲取鎖標記,這時它們處於佇列狀態,既先到先得),一旦執行緒獲得鎖標記後,就轉入就緒狀態,等待OS分配CPU時間片。
    5. suspend()resume()方法:兩個方法配套使用,suspend()使得執行緒進入阻塞狀態,並且不會自動恢復,必須其對應的resume()被呼叫,才能使得執行緒重新進入可執行狀態。典型地,suspend()resume()被用在等待另一個執行緒產生的結果的情形:測試發現結果還沒有產生後,讓執行緒阻塞,另一個執行緒產生了結果後,呼叫resume()使其恢復。
    6. wait()notify()方法:當執行緒呼叫wait()方法後會進入等待佇列(進入這個狀態會釋放所佔有的所有資源,與阻塞狀態不同),進入這個狀態後,是不能自動喚醒的,必須依靠其他執行緒呼叫notify()notifyAll()方法才能被喚醒(由於notify()只是喚醒一個執行緒,但我們由不能確定具體喚醒的是哪一個執行緒,也許我們需要喚醒的執行緒不能夠被喚醒, 因此在實際使用時,一般都用notifyAll()方法,喚醒有所執行緒),執行緒被喚醒後會進入鎖池,等待獲取鎖標記。 wait() 使得執行緒進入阻塞狀態,它有兩種形式:一種允許指定以ms為單位的時間作為引數,另一種沒有引數。前者當對應的notify()被呼叫或超出指定時間時執行緒重新進入可執行狀態即就緒狀態,後者則必須對應的notify()被呼叫。 當呼叫wait()後,執行緒會釋放掉它所佔有的“鎖標誌”,從而使執行緒所在物件中的其它synchronized資料可被別的執行緒使用。wait()notify()因為會對物件的“鎖標誌”進行操作,所以它們必須在synchronized函式或synchronized block中進行呼叫。 如果在non-synchronized函式或non-synchronizedblock中進行呼叫,雖然能編譯通過,但在執行時會發生IllegalMonitorStateException的異常。

執行緒池ThreadPoolExecutor實現原理

我們先看下ThreadPoolExecutor的繼承關係:

public class ThreadPoolExecutor extends AbstractExecutorService { ... }
public abstract class AbstractExecutorService implements ExecutorService { ... }
public interface ExecutorService extends Executor { ... }
public interface Executor { ... }

ThreadPoolExecutor的繼承關係

再看看ThreadPoolExecutor的構造方法瞭解一下這個類:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) { 
    //...省略...
}

構造引數比較多,一個一個說下:

  • corePoolSize:執行緒池中的核心執行緒數;
  • maximumPoolSize:執行緒池最大執行緒數,它表示線上程池中最多能建立多少個執行緒;
  • keepAliveTime:執行緒池中非核心執行緒閒置超時時長(準確來說應該是沒有任務執行時的回收時間,後面會分析);
    • 一個非核心執行緒,如果不幹活(閒置狀態)的時長超過這個引數所設定的時長,就會被銷燬掉
    • 如果設定allowCoreThreadTimeOut(boolean value),則也會作用於核心執行緒
  • TimeUnit:時間單位。可選的單位有分鐘(MINUTES),秒(SECONDS),毫秒(MILLISECONDS) 等;
  • workQueue:任務的阻塞佇列,快取將要執行的Runnable任務,由各執行緒輪詢該任務佇列獲取任務執行。可以選擇以下幾個阻塞佇列。
    • ArrayBlockingQueue:是一個基於陣列結構的有界阻塞佇列,此佇列按 FIFO(先進先出)原則對元素進行排序。
    • LinkedBlockingQueue:一個基於連結串列結構的阻塞佇列,此佇列按FIFO (先進先出) 排序元素,吞吐量通常要高於ArrayBlockingQueue。靜態工廠方法Executors.newFixedThreadPool()使用了這個佇列。
    • SynchronousQueue:一個不儲存元素的阻塞佇列。每個插入操作必須等到另一個執行緒呼叫移除操作,否則插入操作一直處於阻塞狀態,吞吐量通常要高於LinkedBlockingQueue,靜態工廠方法Executors.newCachedThreadPool使用了這個佇列。
    • PriorityBlockingQueue:一個具有優先順序的無限阻塞佇列。
  • ThreadFactory:執行緒建立的工廠。可以進行一些屬性設定,比如執行緒名,優先順序等等,有預設實現。
  • RejectedExecutionHandler:任務拒絕策略,當執行執行緒數已達到maximumPoolSize,佇列也已經裝滿時會呼叫該引數拒絕任務,預設情況下是AbortPolicy,表示無法處理新任務時丟擲異常。以下是JDK1.5提供的四種策略。
    • AbortPolicy:直接丟擲異常。
    • CallerRunsPolicy:只用呼叫者所線上程來執行任務。
    • DiscardOldestPolicy:丟棄佇列裡最近的一個任務,並執行當前任務。
    • DiscardPolicy:不處理,丟棄掉。
    • 當然也可以根據應用場景需要來實現RejectedExecutionHandler介面自定義策略。如記錄日誌或持久化不能處理的任務。

ThreadPoolExecutor的狀態變數

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

// runState is stored in the high-order bits
private static final int RUNNING    = -1 << COUNT_BITS;
private static final int SHUTDOWN   =  0 << COUNT_BITS;
private static final int STOP       =  1 << COUNT_BITS;
private static final int TIDYING    =  2 << COUNT_BITS;
private static final int TERMINATED =  3 << COUNT_BITS;

// Packing and unpacking ctl
private static int runStateOf(int c)     { return c & ~CAPACITY; }
private static int workerCountOf(int c)  { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }

其中ctl是ThreadPoolExecutor的同步狀態變數。

workerCountOf()方法取得當前執行緒池的執行緒數量,演算法是將ctl的值取低29位。

runStateOf()方法取得執行緒池的狀態,演算法是將ctl的值取高3位:

  1. RUNNING 111 表示正在執行
  2. SHUTDOWN 000 表示拒絕接收新的任務
  3. STOP 001 表示拒絕接收新的任務並且不再處理任務佇列中剩餘的任務,並且中斷正在執行的任務。
  4. TIDYING 010 表示所有執行緒已停止,準備執行terminated()方法。
  5. TERMINATED 011 表示已執行完terminated()方法。

當我們向執行緒池提交任務時,通常使用execute()方法,接下來就先從該方法開始分析。

execute()方法

在分析execute程式碼之前,需要先說明下,我們都知道執行緒池是維護了一批執行緒來處理使用者提交的任務,達到執行緒複用的目的,執行緒池維護的這批執行緒被封裝成了Worker

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();
    //情況1
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    //情況2
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    //情況3
    else if (!addWorker(command, false))
        reject(command);
}

以上程式碼對應了三種情況:

  1. 執行緒池的執行緒數量小於corePoolSize核心執行緒數量,開啟核心執行緒執行任務。
  2. 執行緒池的執行緒數量不小於corePoolSize核心執行緒數量,或者開啟核心執行緒失敗,嘗試將任務以非阻塞的方式新增到任務佇列。
  3. 任務佇列已滿導致新增任務失敗,開啟新的非核心執行緒執行任務。

執行緒池主要流程

回顧FixedThreadPool,因為它配置的corePoolSize與maximumPoolSize相等,所以不會執行到情況3,並且因為workQueue為預設的LinkedBlockingQueue,其長度為Integer.MAX_VALUE,幾乎不可能出現任務無法被新增到workQueue的情況,所以FixedThreadPool的所有任務執行在核心執行緒中。

CachedThreadPool的corePoolSize為0,表示它不會執行到情況1,因為它的maximumPoolSize為Integer.MAX_VALUE,所以幾乎沒有執行緒數量上限,因為它的workQueue為SynchronousQueue,所以當執行緒池裡沒有閒置的執行緒SynchronousQueue就會新增任務失敗,因此會執行到情況3新增新的執行緒執行任務。

從上面execute()的原始碼可以看出addWorker()方法是重中之重,馬上來看下它的實現。

addWorker()方法

 private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    //使用CAS機制輪詢執行緒池的狀態,如果執行緒池處於SHUTDOWN及大於它的狀態則拒絕執行任務
    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;

        //使用CAS機制嘗試將當前執行緒數+1
        //如果是核心執行緒當前執行緒數必須小於corePoolSize 
        //如果是非核心執行緒則當前執行緒數必須小於maximumPoolSize
        //如果當前執行緒數小於執行緒池支援的最大執行緒數CAPACITY 也會返回失敗
        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
        }
    }

    //這裡已經成功執行了CAS操作將執行緒池數量+1,下面建立執行緒
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        w = new Worker(firstTask);
        //Worker內部有一個Thread,並且執行Worker的run方法,因為Worker實現了Runnable
        final Thread t = w.thread;
        if (t != null) {
            //這裡必須同步在狀態為執行的情況下將Worker新增到workers中
            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);  //把新建的woker執行緒放入集合儲存,這裡使用的是HashSet
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            //如果新增成功則執行執行緒
            if (workerAdded) {
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        //如果woker啟動失敗,則進行一些善後工作,比如說修改當前woker數量等等
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

addWorker這個方法先嚐試線上程池執行狀態為RUNNING並且執行緒數量未達上限的情況下通過CAS操作將執行緒池數量+1,接著在ReentrantLock同步鎖的同步保證下判斷執行緒池為執行狀態,然後把Worker新增到HashSet workers中。如果新增成功則執行Worker的內部執行緒。

Worker是什麼

Worker是ThreadPoolExecutor的內部類,原始碼如下:

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(0, 1)) {
            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) {
            }
        }
    }
}

Worker構造方法指定了第一個要執行的任務firstTask,並通過執行緒池的執行緒工廠建立執行緒。可以發現這個執行緒的引數為this,即Worker物件,因為Worker實現了Runnable因此可以被當成任務執行,執行的即Worker實現的run方法:

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

runWorker()方法

因為Worker為ThreadPoolExecutor的內部類,因此runWorker方法實際是ThreadPoolExecutor定義的:

//ThreadPoolExecutor類中
final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    // 因為Worker的建構函式中setState(-1)禁止了中斷,這裡的unclock用於恢復中斷
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        //一般情況下,task都不會為空(特殊情況上面註釋中也說明了),因此會直接進入迴圈體中
        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();
                } 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 {
                //這裡設為null,也就是迴圈體再執行的時候會呼叫getTask方法
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        //當指定任務執行完成,阻塞佇列中也取不到可執行任務時,會進入這裡,做一些善後工作
        //比如在corePoolSize跟maximumPoolSize之間的woker會進行回收
        processWorkerExit(w, completedAbruptly);
    }
}

這個方法是執行緒池複用執行緒的核心程式碼,注意Worker繼承了AbstractQueuedSynchronizer,在執行每個任務前通過lock方法加鎖,執行完後通過unlock方法解鎖,這種機制用來防止執行中的任務被中斷。在執行任務時先嚐試獲取firstTask,即構造方法傳入的Runnable物件,然後嘗試從getTask方法中獲取任務佇列中的任務。在任務執行前還要再次判斷執行緒池是否已經處於STOP狀態或者執行緒被中斷。

在runWorker中,每一個Worker在getTask()成功之後都要獲取Worker的鎖之後執行,也就是說執行中的Worker不會中斷。因為核心執行緒一般在空閒的時候會一直阻塞在獲取Task上,也只有中斷才可能導致其退出。這些阻塞著的Worker就是空閒的執行緒(當然,非核心執行緒阻塞之後也是空閒執行緒)。如果設定了keepAliveTime>0,那非核心執行緒會在空閒狀態下等待keepAliveTime之後銷燬,直到最終的執行緒數量等於corePoolSize

woker執行緒的執行流程就是首先執行初始化時分配給的任務,執行完成以後會嘗試從阻塞佇列中獲取可執行的任務,如果指定時間內仍然沒有任務可以執行,則進入銷燬邏輯呼叫processWorkerExit()方法。
注:這裡只會回收corePoolSize與maximumPoolSize直接的那部分woker

getTask()方法

這裡getTask()方法是要重點說明的,它的實現跟我們構造引數keepAliveTime存活時間有關。我們都知道keepAliveTime代表了執行緒池中的執行緒(即woker執行緒)的存活時間,如果到期則回收woker執行緒,這個邏輯的實現就在getTask中。

getTask()方法就是去阻塞佇列中取任務,使用者設定的存活時間,就是從這個阻塞佇列中取任務等待的最大時間,如果getTask返回null,意思就是woker等待了指定時間仍然沒有取到任務,此時就會跳過迴圈體,進入woker執行緒的銷燬邏輯。

private Runnable getTask() {
    boolean timedOut = false; 
            
           

相關推薦

Java執行ThreadPoolExecutor實現原理

引言 執行緒池:可以理解為緩衝區,由於頻繁的建立銷燬執行緒會帶來一定的成本,可以預先建立但不立即銷燬,以共享方式為別人提供服務,一來可以提供效率,再者可以控制執行緒無線擴張。合理利用執行緒池能夠帶來三個好處: 降低資源消耗。通過重複利用已建立的執行緒降低執行緒建立和銷燬造

Java執行

概念 執行緒池好處 降低資源消耗:重複利用執行緒,從而降低建立和銷燬造成的消耗 提高響應速度:任務到達時,可以不需要等到執行緒建立就能立即執行 提高執行緒的可管理性:執行緒會耗盡資源,降低穩定性,執行緒池可以統一分配、調優、監控 執行緒池組成

Java執行ThreadPoolExecutor實現原理和原始碼分析(五)

章節概覽、 1、概述 執行緒池的顧名思義,就是執行緒的一個集合。需要用到執行緒,從集合裡面取出即可。這樣設計主要的作用是優化執行緒的建立和銷燬而造成的資源浪費的情況。Java中的執行緒池的實現主要是JUC下面的ThreadPoolExecutor類完成的。下面

從原始碼角度來分析執行-ThreadPoolExecutor實現原理

作為一名Java開發工程師,想必效能問題是不可避免的。通常,在遇到效能瓶頸時第一時間肯定會想到利用快取來解決問題,然而快取雖好用,但也並非萬能,某些場景依然無法覆蓋。比如:需要實時、多次呼叫第三方API時,該場景快取則無法適用。 然多執行緒併發的方式則很好的解決了上述問題。   但若每次都在任務開始

Java執行執行的工作原理詳解(下)

接著上篇文章,我接下來繼續介紹執行緒池的工作原理,如果你還沒有看上篇,我建議最好瀏覽一下:執行緒池的工作原理詳解(上) Executors 工具類 1.定義 Executors是java執行緒池的工廠類,通過它可以快速初始化一個符合業務需求的執行緒池。

執行和Executor框架

  一 使用執行緒池的好處 二 Executor 框架 2.1 簡介 2.2 Executor框架結構(主要由三部分構成)  2.3 Executor框架使用說明示意圖 三 ThreadPoolExecutor詳解 3.1 Thread

Java 併發程式設計深入學習——執行及其實現原理

Java執行緒池介紹   執行緒池,從字面含義來看,是指管理一組同構工作執行緒的資源池。執行緒池是與工作佇列(work Queue)密切相關的,其中工作佇列中儲存了所有等待執行的任務。工作者執行緒(Work Thread)的任務很簡單:從工作佇列中獲取一個任務,執行任務,然

Java網際網路程式設計——深入分析java執行實現原理

月亮姨的嘮叨: 執行緒是稀缺資源,如果被無限制的建立,不僅會消耗系統資源,還會降低系統的穩定性,合理的使用執行緒池對執行緒進行統一分配、調優和監控,有以下好處: 1、降低資源消耗; 2、提高響應速度; 3、提高執行緒的可管理性。 Java1.5中引入的Executo

深入原始碼分析Java執行實現原理

程式的執行,其本質上,是對系統資源(CPU、記憶體、磁碟、網路等等)的使用。如何高效的使用這些資源是我們程式設計優化演進的一個方向。今天說的執行緒池就是一種對CPU利用的優化手段。 網上有不少介紹如何使用執行緒池的文章,那我想說點什麼呢?我希望通過學習執行緒池原理,明白所有

深入分析java執行實現原理

前言 執行緒是稀缺資源,如果被無限制的建立,不僅會消耗系統資源,還會降低系統的穩定性,合理的使用執行緒池對執行緒進行統一分配、調優和監控,有以下好處: 1、降低資源消耗; 2、提高響應速度; 3、提高執行緒的可管理性。 Java1.5中引入的Executor框架

java.util.concurrent 執行實現原理

ThreadPoolExecutor構造 corePoolSize:執行緒池中的執行緒數 maximumPoolSize:允許的最大執行緒數 keepAliveTime:當前執行緒的空閒時間,如果超時會自動釋放執行緒資源預設 0 TimeUnit:引數的時間單元

Java執行ThreadPoolExecutor原理探究

一、 前言 執行緒池主要解決兩個問題:一方面當執行大量非同步任務時候執行緒池能夠提供較好的效能,,這是因為使用執行緒池可以使每個任務的呼叫開銷減少(因為執行緒池執行緒是可以複用的)。另一方面執行緒池提供了一種資源限制和管理的手段,比如當執行一系列任務時候對執行緒的管理,每個ThreadPool

JAVA執行建立和匿名內部類

前言 看多執行緒時,發現一些匿名內部類的東西,然後就來總結一下。   1.繼承Thread類 在類上實現匿名內部類 public class Demo1 { public static void main(String[] args) { Thread t = new T

Java執行安全的單例模式----靜態內部類

單例模式作為一種常見的設計模式,在程式中非常常見,主要是為了保證一個類只有一個唯一的物件。 從簡單的“餓漢式”、“懶漢式”→利用 synchronized 和 複雜的“雙重校驗DCL模式”,是一個考慮執行緒安全的過程(其實靜態的餓漢式單例模式也是執行緒安全的,

Linux執行

首先,執行緒池是什麼?顧名思義,就是把一堆開闢好的執行緒放在一個池子裡統一管理,就是一個執行緒池。   其次,為什麼要用執行緒池,難道來一個請求給它申請一個執行緒,請求處理完了釋放執行緒不行麼?也行,但是如果建立執行緒和銷燬執行緒的時間比執行緒處理請求的時間長,而且請求很多的情況下,我們的CPU資源都浪費在

java執行簡單實現

以前做的東西,實現一個簡單的多執行緒機制,開始之前,現說說原理性的東西吧,下面是我在ibm開發者上搜到的內容 執行緒池的技術背景   在面向物件程式設計中,建立和銷燬物件是很費時間的,因為建立一個物件要獲取記憶體資源或者其它更多資源。在Java中更是如此,虛擬機器將

Java執行ThreadPoolExecutor解析及Executors類中提供的靜態方法來建立執行

上面的程式碼可能看起來不是那麼容易理解,下面我們一句一句解釋:   首先,判斷提交的任務command是否為null,若是null,則丟擲空指標異常;   接著是這句,這句要好好理解一下: if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(c

Java中的執行——ThreadPoolExecutor原理

private boolean addWorker(Runnable firstTask, boolean core) { retry: //死迴圈更新狀態 for (;;) { int c = ctl.get(); int

Java執行join方法

join是java多執行緒的裡的方法。它的作用是什麼? java中的任意程式碼段,都可能會被任意的執行緒執行。程式碼段中可以是任意的程式碼,比如,啟動了一個執行緒。如果是這種情況,就可以用join方法了。 假設當前程式碼段A啟動了執行緒t,執行當前的程式碼的執行緒假定為a,

java執行實現原理(netty)

部落格已經好久都沒有寫了,感覺自己變慵懶了。。。這本來也是應該早就應該要寫的。。。 在前面讀netty原始碼的時候就可以看到netty本身就自己實現了一個執行緒池,而且也自己實現了future,並且實現的功能更加的強大。。。future還可以新增listener,這個剛開始