Java并發(fā)之線(xiàn)程狀態(tài)及創(chuàng)建(1)

一、狀態(tài)解讀

Java線(xiàn)程狀態(tài)遷移.png

1、New 初始狀態(tài)

創(chuàng)建線(xiàn)程后,未運(yùn)行

2、Runnable 可運(yùn)行狀態(tài)

可能在運(yùn)行也可能在等待CPU時(shí)間片
同時(shí)也包含了操作系統(tǒng)線(xiàn)程的Ready 和 Running

著重說(shuō)一下Thread.yield()
Thread.yield()方法作用是:暫停當(dāng)前正在執(zhí)行的線(xiàn)程對(duì)象(及放棄當(dāng)前擁有的cup資源),并執(zhí)行其他線(xiàn)程。

yield()做的是讓當(dāng)前運(yùn)行線(xiàn)程回到可運(yùn)行狀態(tài),以允許具有相同優(yōu)先級(jí)的其他線(xiàn)程獲得運(yùn)行機(jī)會(huì)。因此,使用yield()的
目的是讓相同優(yōu)先級(jí)的線(xiàn)程之間能適當(dāng)?shù)妮嗈D(zhuǎn)執(zhí)行。但是,實(shí)際中無(wú)法保證yield()達(dá)到讓步目的,因?yàn)樽尣降木€(xiàn)程還有可能被
線(xiàn)程調(diào)度程序再次選中。

結(jié)論:yield()從未導(dǎo)致線(xiàn)程轉(zhuǎn)到等待/睡眠/阻塞狀態(tài)。在大多數(shù)情況下,yield()將導(dǎo)致線(xiàn)程從運(yùn)行狀態(tài)轉(zhuǎn)到可運(yùn)行狀態(tài),但有可能沒(méi)有效果。

3、Blocked 阻塞

等待獲取一個(gè)Synchronized鎖,如果搶占到鎖就會(huì)離開(kāi)此狀態(tài)。

4、Waiting 等待

等待其它線(xiàn)程顯示的喚醒,否則一直等待下去。

進(jìn)入 退出
沒(méi)有設(shè)置Time out參數(shù)的Object.wait() Object.notify() 或 Object.notifyAll()
沒(méi)有設(shè)置Time out參數(shù)的Thread.join() 被調(diào)用的線(xiàn)程執(zhí)行完畢
LockSupport.park() LockSupport.unpark(Thread thread)

5、Timed Waiting 超時(shí)等待

進(jìn)入 退出
Object.wait(Long) Object.notify() 或 Object.notifyAll()
Thread.join(Long) 超時(shí)退出 或 被調(diào)用的線(xiàn)程執(zhí)行完畢
Thread.sleep(Long) 超時(shí)退出
LockSupport.parkNanos(Long) LockSupport.unpark()
LockSupport.parkUntil(Long) LockSupport.unpark()

6、Terminated 終止?fàn)顟B(tài)

當(dāng)線(xiàn)程的run()方法執(zhí)行完畢或者主線(xiàn)程的main()方法完畢,就終止了,也許在這一刻,該線(xiàn)程還是存活的,但是它就要被終止了。

在一個(gè)終止的線(xiàn)程上調(diào)用start()方法會(huì)拋出異常java.lang.IllegalThreadStateException,線(xiàn)程一旦被終止,就無(wú)法再次運(yùn)行。

二、創(chuàng)建

Java線(xiàn)程的創(chuàng)建分為四種方式:

1)繼承Tread類(lèi)

    public class MyThread extends Thread {
        public void run() {
            System.out.println("我是繼承于Thread的線(xiàn)程類(lèi)");
        }
    }
    
    ==================分割線(xiàn)====================

    @Slf4j
    public class JunitTest {
        @Test
        public void test() throws InterruptedException {
            MyThread thread = new MyThread();

            thread.start();
    
            Thread.sleep(3000);
        }
    }

繼承Thread類(lèi),重寫(xiě)其run()方法,然后通過(guò)start()方法調(diào)用即可,如果直接調(diào)用run()方法,那么就相當(dāng)于調(diào)用同步方法,只有調(diào)用start()才是啟動(dòng)線(xiàn)程的正解。

2)實(shí)現(xiàn)Runnable接口

    public class MyThread implements Runnable {
        @Override
        public void run() {
            System.out.println("我是實(shí)現(xiàn)Runnable接口的線(xiàn)程類(lèi)");
        }
    }

    ==================分割線(xiàn)====================

    @Slf4j
    public class JunitTest {
        @Test
        public void test() throws InterruptedException {
            MyThread myThread = new MyThread();
            
            // 傳入MyThread實(shí)例
            Thread thread = new Thread(myThread);
    
            thread.start();
            
            Thread.sleep(3000);
        }
    }

實(shí)現(xiàn)Runnable接口,重寫(xiě)其run()方法。
限于第一種方式,受繼承的限制,第二種比第一種方式能好一些

3)實(shí)現(xiàn)Callable接口

    public class MyThread implements Callable<String> {
    
        @Override
        public String call() throws Exception {
            System.out.println("我是實(shí)現(xiàn)Callable接口的線(xiàn)程類(lèi)");
            return "ok";
        }
    }

    ==================分割線(xiàn)====================

    @Test
    public void test() throws Exception {
        Callable<String> callable = new MyThread();
    
        FutureTask<String> futureTask = new FutureTask<>(callable);
    
        Thread thread = new Thread(futureTask);
    
        thread.start();
    
        Thread.sleep(3000);
    }

覆寫(xiě)call()方法,且支持返回值!

4)通過(guò)線(xiàn)程池

可以通過(guò)Executors來(lái)創(chuàng)建幾種不同類(lèi)型的線(xiàn)程池。Executors是一個(gè)線(xiàn)程池工廠,提供了創(chuàng)建線(xiàn)程池的很多方法。

1)SingleThreadPoolExecutor

只有一個(gè)線(xiàn)程的線(xiàn)程池。多個(gè)任務(wù)被提交到該線(xiàn)程池,先被緩存到隊(duì)列(隊(duì)列長(zhǎng)度為Integer.MAX_VALUE),按照FIFO先進(jìn)先出的原則進(jìn)行任務(wù)處理。

2)FixedThreadPool

固定大小的線(xiàn)程池,內(nèi)部存儲(chǔ)的線(xiàn)程數(shù)量是固定的,和上面的處理流程極為類(lèi)似,但是該線(xiàn)程池可以處理多個(gè)任務(wù),多個(gè)任務(wù)被提交到線(xiàn)程池,按照以下過(guò)程進(jìn)行處理:

1)如果線(xiàn)程的數(shù)量未達(dá)到設(shè)置的數(shù)量,線(xiàn)程池會(huì)創(chuàng)建線(xiàn)程來(lái)處理任務(wù)。

2)如果線(xiàn)程池里的線(xiàn)程數(shù)量達(dá)到了設(shè)置的數(shù)量,則取出空閑的線(xiàn)程執(zhí)行任務(wù)

3)如果沒(méi)有空閑線(xiàn)程,則將任務(wù)緩存到隊(duì)列(隊(duì)列長(zhǎng)度為Integer.MAX_VALUE),當(dāng)有空閑線(xiàn)程時(shí),按照FIFO的原則進(jìn)行任務(wù)處理

嚴(yán)格按照 1 -> 2 -> 3的過(guò)程進(jìn)行處理。

3)CachedThreadPool

創(chuàng)建帶緩存的線(xiàn)程池,這種線(xiàn)程池可以回收空閑線(xiàn)程,當(dāng)任務(wù)到達(dá)后,直接使用空閑線(xiàn)程,沒(méi)有空閑線(xiàn)程時(shí),新建線(xiàn)程。線(xiàn)程池核心長(zhǎng)度為0,最大長(zhǎng)度為Integer.MAX_VALUE。
用戶(hù)可以傳入線(xiàn)程池的核心線(xiàn)程數(shù)(最小線(xiàn)程數(shù)),最大線(xiàn)程數(shù)量,保持時(shí)間,時(shí)間單位,阻塞隊(duì)列這些參數(shù),最大線(xiàn)程數(shù)設(shè)置為jvm可用的cpu數(shù)為宜。

4)ScheduledThreadPool

一個(gè)可定期或者延時(shí)執(zhí)行任務(wù)的線(xiàn)程池

5) WorkStealingPool

創(chuàng)建擁有足夠線(xiàn)程數(shù)的線(xiàn)程池來(lái)維持相應(yīng)的并行級(jí)別,通過(guò)使用隊(duì)列來(lái)減少競(jìng)爭(zhēng),默認(rèn)為CPU的數(shù)量。它會(huì)通過(guò)工作竊取的方式,使得多核CPU不會(huì)閑置,總會(huì)有活著的線(xiàn)程讓CPU去運(yùn)行。

所謂工作竊取,指的是閑置的線(xiàn)程去處理本不屬于它的任務(wù)。

在實(shí)際項(xiàng)目里,我們很少成規(guī)模的手動(dòng)創(chuàng)建線(xiàn)程,一般都是使用線(xiàn)程池(池技術(shù))將線(xiàn)程的創(chuàng)建、銷(xiāo)毀、保留及其它管理工作交給線(xiàn)程池,用戶(hù)無(wú)需知道其內(nèi)部細(xì)節(jié),即可使用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容