成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

淺談Java并發(fā)編程系列(六) —— 線程池的使用

Vicky / 2515人閱讀

摘要:線程池的作用降低資源消耗。通過重復(fù)利用已創(chuàng)建的線程降低線程創(chuàng)建和銷毀造成的資源浪費。而高位的部分,位表示線程池的狀態(tài)。當(dāng)線程池中的線程數(shù)達(dá)到后,就會把到達(dá)的任務(wù)放到中去線程池的最大長度。默認(rèn)情況下,只有當(dāng)線程池中的線程數(shù)大于時,才起作用。

線程池的作用

降低資源消耗。通過重復(fù)利用已創(chuàng)建的線程降低線程創(chuàng)建和銷毀造成的資源浪費。

提高響應(yīng)速度。當(dāng)任務(wù)到達(dá)時,不需要等到線程創(chuàng)建就能立即執(zhí)行。

方便管理線程。線程是稀缺資源,如果無限制地創(chuàng)建,不僅會消耗系統(tǒng)資源,還會降低系統(tǒng)的穩(wěn)定性,使用線程池可以對線程進(jìn)行統(tǒng)一的分配,優(yōu)化及監(jiān)控。

設(shè)置線程池大小

設(shè)置線程池的大小可以從以下幾個方面分析入手:

系統(tǒng)中有多少個cpu?

多大的內(nèi)存?

任務(wù)是計算密集型、I/O密集集還是二者皆可?

是否需要像JDBC連接這樣的稀缺資源?

對于計算密集型的任務(wù),在擁有N個cpu的機(jī)器上,通常將線程池大小設(shè)置為N+1時,能夠?qū)崿F(xiàn)最優(yōu)的利用率。 對于包含I/O操作或者其他阻塞操作的任務(wù),由于線程并不會一直執(zhí)行,因此線程池的規(guī)模應(yīng)該更大。
可通過如下公式進(jìn)行估計:
$$N_{threads} = N_{cpu}*U_{cpu}*(1+frac{W}{C})$$
其中:
$$ U_{cpu} = target CPU utilization, 0 le U_{cpu} le 1$$
$$ frac{W}{C} = ration of wait time to compute time$$
可以通過Rumtime來獲得CUP的數(shù)目:

int N_CPUS = Runtime.getRuntime().availableProcessor();

當(dāng)然,CPU周期并不是唯一影響線程池大小的資源,還包括內(nèi)存、文件句柄、套接字句柄和數(shù)據(jù)庫連接等。計算方法:計算每個任務(wù)對該資源的需求量,然后用該資源的可用總量除以每個任務(wù)的需要量,所得結(jié)果就是線程池的大小上限。

線程池的實現(xiàn)原理 ThreadPoolExecutor

Java的線程池針對不同應(yīng)用的場景,主要有固定長度類型、可變長度類型以及定時執(zhí)行等幾種。針對這幾種類型的創(chuàng)建,java中有一個專門的Executors類提供了一系列的方法封裝了具體的實現(xiàn)。這些功能和用途不一樣的線程池主要依賴ThreadPoolExecutor, ScheduledThreadPoolExecutor等幾個類。如前面文章討論所說,這些類和相關(guān)類的主要結(jié)構(gòu)如下:

ThreadPoolExecutor是實現(xiàn)線程池最核心的類之一。在分析ThreadPoolExecutor的實現(xiàn)原理之前,讓來看看實現(xiàn)線程池需要考慮的點:
從線程池本身的定義來看,它是將一組事先創(chuàng)建好的線程放在一個資源池里,當(dāng)需要的時候就將該線程分配給具體的任務(wù)來執(zhí)行。那么,這個池子的大小如何確定?線程池肯定要面臨多個線程資源訪問的情況,是不是本身的結(jié)構(gòu)要保證線程安全呢?如果線程池創(chuàng)建好之后后續(xù)有若干任務(wù)使用了線程資源,當(dāng)池里面的資源使用完之后要如何安排?是給線程擴(kuò)容,創(chuàng)建更多的線程資源,還是增加一個隊列,讓一些任務(wù)先在里面排隊呢?在一些極端的情況下,比如任務(wù)數(shù)量實在太多線程池處理不過來,對于這些任務(wù)怎么處理呢?線程執(zhí)行的時候會碰到異?;蚨煎e誤的情況,這些異常要如何處理?如何保證這些異常的處理不會導(dǎo)致線程池其他任務(wù)的正常運行不出錯呢?

總結(jié)一下,這些問題可以歸納為如下幾點:

線程池的結(jié)構(gòu);

線程池的任務(wù)分配策略;

線程池的異常和錯誤處理機(jī)制;

下面結(jié)合ThreadPoolExecutor的實現(xiàn)源碼來詳細(xì)分析一下。

線程數(shù)量和線程池狀態(tài)
    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是線程池的主要控制狀態(tài),它是一個AtomicInteger的數(shù)值,它表示了兩部分內(nèi)容:

workerCount, 表示有效線程數(shù);

runState, 表示線程池狀態(tài),是否運行,停止等。

ctl是用一個integer(32)來包含線程池狀態(tài)和數(shù)量的表示,高三位為線程池的狀態(tài),后(2^29)-1為線程數(shù)限制。 這就是為什么前面用一個Integer.SIZE-3來作為位數(shù)。這樣這個整數(shù)的0-28位表示的就是線程的數(shù)目。而高位的部分,29-31位表示線程池的狀態(tài)。這里定義的主要有5種狀態(tài),分別對應(yīng)值是從-1到3. 他們對應(yīng)著線程的running, shutdown, stop, tidying, terminated這幾個狀態(tài)。

線程池的結(jié)構(gòu)

除了以上部分外,線程池里還有如下成員:

    private final BlockingQueue workQueue;
    
    private final ReentrantLock mainLock = new ReentrantLock();

    /**
     * Set containing all worker threads in pool. Accessed only when holding mainLock.
     */
    private final HashSet workers = new HashSet();

    /**
     * Wait condition to support awaitTermination
     */
    private final Condition termination = mainLock.newCondition();

    /**
     * Tracks largest attained pool size. Accessed only under
     * mainLock.
     */
    private int largestPoolSize;

    /**
     * Counter for completed tasks. Updated only on termination of
     * worker threads. Accessed only under mainLock.
     */
    private long completedTaskCount;

    private volatile ThreadFactory threadFactory;

    /**
     * Handler called when saturated or shutdown in execute.
     */
    private volatile RejectedExecutionHandler handler;

    /**
     * Timeout in nanoseconds for idle threads waiting for work.
     * Threads use this timeout when there are more than corePoolSize
     * present or if allowCoreThreadTimeOut. Otherwise they wait
     * forever for new work.
     */
    private volatile long keepAliveTime;

    /**
     * If false (default), core threads stay alive even when idle.
     * If true, core threads use keepAliveTime to time out waiting
     * for work.
     */
    private volatile boolean allowCoreThreadTimeOut;

    /**
     * Core pool size is the minimum number of workers to keep alive
     * (and not allow to time out etc) unless allowCoreThreadTimeOut
     * is set, in which case the minimum is zero.
     */
    private volatile int corePoolSize;

    /**
     * Maximum pool size. Note that the actual maximum is internally
     * bounded by CAPACITY.
     */
    private volatile int maximumPoolSize;

workerQueue: 一個BlockingQueue隊列,本身的結(jié)構(gòu)可以保證訪問的線程安全。相當(dāng)于一個排隊等待隊列。當(dāng)線程池的線程數(shù)達(dá)到corePoolSize的時候,一些需要等待執(zhí)行的線程就放到這個隊列里等待。
worker: 一個HashSet 集合。線程池里所有可以立即執(zhí)行的線程都放在這個集合里。
mainLock: 一個訪問workers所需要使用的鎖。從前面的workQueue,workers這兩個結(jié)構(gòu)可以看出,如果要往線程池里面增加執(zhí)行任務(wù)或者執(zhí)行完畢一個任務(wù),都要訪問這兩個結(jié)構(gòu)。所以大多數(shù)情況下為了保證線程安全,就需要使用mainLock這個鎖。
corePoolSize:處于活躍狀態(tài)的最少worker數(shù)目。每個worker會創(chuàng)建一個新的線程去執(zhí)行任務(wù)。在創(chuàng)建了線程池后,默認(rèn)情況下,線程池中并沒有任何線程,而是等待有任務(wù)來才創(chuàng)建線程去執(zhí)行,除非調(diào)用了prestartAllCoreThreads()或prestartCoreThread()方法。當(dāng)線程池中的線程數(shù)達(dá)到corePoolSize后,就會把到達(dá)的任務(wù)放到workerQueue中去;
maximumPoolSize: 線程池的最大長度。當(dāng)線程池里面的線程數(shù)達(dá)到這個數(shù)字時就不能再往里面加了,此時會根據(jù)設(shè)置的handler參數(shù),即拒絕處理任務(wù)策略來處理新到來的任務(wù)。
keepAliveTime: 表示線程沒有任務(wù)執(zhí)行時最多保持多久時間會終止。默認(rèn)情況下,只有當(dāng)線程池中的線程數(shù)大于corePoolSize時,keepAliveTime才起作用。當(dāng)線程池中的線程數(shù)大于corePoolSize時,如果一個線程空閑的時間達(dá)到keepAliveTime,則會終止,直到線程池中的線程數(shù)不超過corePoolSize。但是如果調(diào)用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數(shù)不大于corePoolSize時,keepAliveTime參數(shù)也會起作用,直到線程數(shù)為0。
threadFactory: 線程工廠,主要用來創(chuàng)建線程;
largestPoolSize: 用來記錄線程池中曾經(jīng)有過的最大線程數(shù),跟線程池的容易沒有任何關(guān)系。
handler: 表示當(dāng)拒絕處理任務(wù)時的策略,有以四種取值:

ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常。 
ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),但是不拋出異常。 
ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務(wù),然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過程)
ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù) 
任務(wù)的執(zhí)行者——Worker
    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) {
                }
            }
        }
    }

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/66069.html

相關(guān)文章

  • 我的阿里之路+Java面經(jīng)考點

    摘要:我的是忙碌的一年,從年初備戰(zhàn)實習(xí)春招,年三十都在死磕源碼,三月份經(jīng)歷了阿里五次面試,四月順利收到實習(xí)。因為我心理很清楚,我的目標(biāo)是阿里。所以在收到阿里之后的那晚,我重新規(guī)劃了接下來的學(xué)習(xí)計劃,將我的短期目標(biāo)更新成拿下阿里轉(zhuǎn)正。 我的2017是忙碌的一年,從年初備戰(zhàn)實習(xí)春招,年三十都在死磕JDK源碼,三月份經(jīng)歷了阿里五次面試,四月順利收到實習(xí)offer。然后五月懷著忐忑的心情開始了螞蟻金...

    姘擱『 評論0 收藏0
  • 淺談Java并發(fā)編程系列(一)—— 如何保證線程安全

    摘要:比如需要用多線程或分布式集群統(tǒng)計一堆用戶的相關(guān)統(tǒng)計值,由于用戶的統(tǒng)計值是共享數(shù)據(jù),因此需要保證線程安全。如果類是無狀態(tài)的,那它永遠(yuǎn)是線程安全的。參考探索并發(fā)編程二寫線程安全的代碼 線程安全類 保證類線程安全的措施: 不共享線程間的變量; 設(shè)置屬性變量為不可變變量; 每個共享的可變變量都使用一個確定的鎖保護(hù); 保證線程安全的思路: 1. 通過架構(gòu)設(shè)計 通過上層的架構(gòu)設(shè)計和業(yè)務(wù)分析來避...

    mylxsw 評論0 收藏0
  • 淺談Java并發(fā)編程系列(四)—— 原子性、可見性與有序性

    摘要:內(nèi)存模型是圍繞著在并發(fā)過程中如何處理原子性可見性和有序性這個特征來建立的,我們來看下哪些操作實現(xiàn)了這個特性??梢娦钥梢娦允侵府?dāng)一個線程修改了共享變量的值,其他線程能夠立即得知這個修改。 Java內(nèi)存模型是圍繞著在并發(fā)過程中如何處理原子性、可見性和有序性這3個特征來建立的,我們來看下哪些操作實現(xiàn)了這3個特性。 原子性(atomicity): 由Java內(nèi)存模型來直接保證原子性變量操作包括...

    tianren124 評論0 收藏0
  • 淺談Java并發(fā)編程系列(二)—— Java內(nèi)存模型

    摘要:物理計算機(jī)并發(fā)問題在介紹內(nèi)存模型之前,先簡單了解下物理計算機(jī)中的并發(fā)問題?;诟咚倬彺娴拇鎯换ヒ胍粋€新的問題緩存一致性。寫入作用于主內(nèi)存變量,把操作從工作內(nèi)存中得到的變量值放入主內(nèi)存的變量中。 物理計算機(jī)并發(fā)問題 在介紹Java內(nèi)存模型之前,先簡單了解下物理計算機(jī)中的并發(fā)問題。由于處理器的與存儲設(shè)置的運算速度有幾個數(shù)量級的差距,所以現(xiàn)代計算機(jī)加入一層讀寫速度盡可能接近處理器的高速緩...

    Edison 評論0 收藏0
  • 淺談Java并發(fā)編程系列(三)—— volatile型變量

    摘要:禁止指令重排序優(yōu)化。只有當(dāng)線程對變量執(zhí)行的前一個動作是時,才能對執(zhí)行動作并且,只有當(dāng)對變量執(zhí)行的后一個動作是時,線程才能對變量執(zhí)行動作。變量不需要與其他的狀態(tài)變量共同參與不變約束。在某些情況下,的同步機(jī)制性要優(yōu)于鎖。 當(dāng)一個變量定義為volatile之后,它具備兩種特性: 保證此變量對所有線程的可見性,這里的可見性是指當(dāng)一條線程修改了這個變量的值,新值對于其他線程來說是可以立即得知的...

    zxhaaa 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<