成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

一文讀懂Java線程狀態(tài)轉(zhuǎn)換

summerpxy / 631人閱讀

摘要:前言本文描述線程線程狀態(tài)及狀態(tài)轉(zhuǎn)換,不會涉及過多理論,主要以代碼示例說明線程狀態(tài)如何轉(zhuǎn)換。被終止線程執(zhí)行完畢正常結(jié)束或執(zhí)行過程中因未捕獲異常意外終止都會是線程進入被終止狀態(tài)。線程執(zhí)行完畢打印狀態(tài)。

前言

本文描述Java線程線程狀態(tài)及狀態(tài)轉(zhuǎn)換,不會涉及過多理論,主要以代碼示例說明線程狀態(tài)如何轉(zhuǎn)換。

基礎(chǔ)知識 1. 線程狀態(tài)

線程可以有6種狀態(tài):

New(新建)

Runnable(可運行)

Blocked(被阻塞)

Waiting(等待)

Timed waiting(計時等待)

Terminated(被終止)

New:new Thread()后線程的狀態(tài)就是新建。

Runnable:線程一旦調(diào)用start()方法,無論是否運行,狀態(tài)都為Runable,注意Runable狀態(tài)指示表示線程可以運行,不表示線程當下一定在運行,線程是否運行由虛擬機所在操作系統(tǒng)調(diào)度決定。

被阻塞:線程試圖獲取一個內(nèi)部對象的Monitor(進入synchronized方法或synchronized塊)但是其他線程已經(jīng)搶先獲取,那此線程被阻塞,知道其他線程釋放Monitor并且線程調(diào)度器允許當前線程獲取到Monitor,此線程就恢復(fù)到可運行狀態(tài)。

等待:當一個線程等待另一個線程通知調(diào)度器一個條件時,線程進入等待狀態(tài)。

計時等待:和等待類似,某些造成等待的方法會允許傳入超時參數(shù),這類方法會造成計時等待,收到其他線程的通知或者超時都會恢復(fù)到可運行狀態(tài)。

被終止:線程執(zhí)行完畢正常結(jié)束或執(zhí)行過程中因未捕獲異常意外終止都會是線程進入被終止狀態(tài)。

2. 線程狀態(tài)轉(zhuǎn)換

線程從“新建”到“被終止”會歷經(jīng)多次狀態(tài)轉(zhuǎn)換,所有可能的轉(zhuǎn)換如下圖:

【圖一】

觀察狀態(tài)轉(zhuǎn)化圖,我們發(fā)現(xiàn)“可運行”狀態(tài)為所有狀態(tài)的必經(jīng)狀態(tài)。我們分析出四條基本的狀態(tài)轉(zhuǎn)換線路圖。

新建--->可運行--->被終止

新建--->可運行--->被阻塞--->可運行--->被終止

新建--->可運行--->等待--->可運行--->被終止

新建--->可運行--->計時等待--->可運行--->被終止

“新建”和“被終止”狀態(tài)分別為起始和結(jié)束狀態(tài),和“可運行”狀態(tài)不可逆。其他狀態(tài)均能和“可運行”狀態(tài)相互轉(zhuǎn)換。

用代碼說話

讓我們用代碼演示線程狀態(tài)是如何轉(zhuǎn)換的,大家重點關(guān)注兩個問題?

什么操作會改變線程狀態(tài)?

改變的狀態(tài)是如何恢復(fù)的?

一、 新建--->可運行--->被終止

這個狀態(tài)轉(zhuǎn)換時創(chuàng)建的線程生命周期。

/**
 * NEW->RUNNABLE->TERMINATED
 */
public class ThreadStateNRT {

    public static void main(String[] args) {
        Thread thread=new Thread(new Task());
        print(thread.getName(),thread.getState());
        thread.start();
        //等待線程執(zhí)行完畢。
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        print(thread.getName(),thread.getState());
    }

    private static class Task implements Runnable{
        @Override
        public void run() {
            print(Thread.currentThread().getName(),Thread.currentThread().getState());
        }
    }
    private static final String stringFormat="%s:%s";
    private static void print(String threadName,Thread.State state){
        System.out.println(String.format(stringFormat,threadName,state));
    }
}

其中,print()方法用來打印線程信息。后面的代碼示例均不在展示。

運行程序結(jié)果為:

Thread-0:NEW 
Thread-0:RUNNABLE
Thread-0:TERMINATED
二、 新建--->可運行--->被阻塞--->可運行--->被終止

只有一種方法能出現(xiàn)阻塞狀態(tài),那就是synchronized同步原語。我們需要兩個線程其中一個線程被另一個阻塞來展示。

/**
 * NEW->RUNNABLE->BLOCKED->RUNNABLE->TERMINATED
 */
public class ThreadStateNRBRT {
    //鎖
    private static final Object lock=new Object();

    public static void main(String[] args) {
        //輔助線程,制造synchronized狀態(tài)。
        Thread assistantThread = new Thread(new SynTask());
        assistantThread.start();
        try {
            //保證assistantThread先執(zhí)行。
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread showThread = new Thread(new Task());
        print(showThread.getName(), showThread.getState());
        showThread.start();
        print(showThread.getName(),showThread.getState());
        //因為無法判斷顯示線程何時執(zhí)行,所以循環(huán)直到顯示線程執(zhí)行。
        while (true){
            if(showThread.getState()==Thread.State.BLOCKED){
                print(showThread.getName(), Thread.State.BLOCKED);
                break;
            }
        }
        //等待兩個線程執(zhí)行完畢。
        try {
            assistantThread.join();
            showThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //線程執(zhí)行完畢打印狀態(tài)。
        print(showThread.getName(), showThread.getState());
    }

    private static class SynTask implements Runnable {
        @Override
        public void run() {
            //鎖定一定時間
            synchronized (lock){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static class Task implements Runnable {
        @Override
        public void run() {
            synchronized (lock){
                print(Thread.currentThread().getName(),Thread.currentThread().getState());
            }
        }
    }
}

執(zhí)行一下你有可能看到正確結(jié)果:

Thread-1:NEW
Thread-1:RUNNABLE
Thread-1:BLOCKED
Thread-1:RUNNABLE
Thread-1:TERMINATED

為什么是有可能呢?我們調(diào)整一下代碼,例如將加鎖的時間調(diào)小一點:

private static class SynTask implements Runnable {
        @Override
        public void run() {
            //鎖定一定時間
            synchronized (lock){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
}

注意此處Thread.sleep(10),我們只鎖住十毫秒。

再運行一下,控制臺可能打印出這樣的結(jié)果且程序不會結(jié)束:

Thread-1:NEW
Thread-1:RUNNABLE
Thread-1:RUNNABLE

造成以上結(jié)果的原因是我么無法保證兩個線程的執(zhí)行順序,也無法證主線程一定能打印出顯示線程阻塞的狀態(tài)。

         while (true){
            if(showThread.getState()==Thread.State.BLOCKED){
                print(showThread.getName(), Thread.State.BLOCKED);
                break;
            }
        }

所以執(zhí)行在這段代碼死循環(huán)了。

調(diào)整一下代碼,保證不會因為參數(shù)調(diào)整改變線程之間的執(zhí)行順序和打印結(jié)果。

/**
 * NEW->RUNNABLE->BLOCKED->RUNNABLE->TERMINATED
 */
public class ThreadStateNRBRT_New {
    //鎖
    private static final Object lock=new Object();
    //鎖定標志
    private volatile static boolean lockFlag=true;
    //執(zhí)行順序
    private volatile static int order=0;

    public static void main(String[] args) {
        //展示線程
        Thread showThread = new Thread(new Task());
        print(showThread.getName(), showThread.getState());
        showThread.start();
        print(showThread.getName(), showThread.getState());
        //輔助線程,制造synchronized狀態(tài)。
        Thread assistantThread = new Thread(new SynTask());
        assistantThread.start();


        //循環(huán)讀取展示線程狀態(tài),直到讀到展示線程狀態(tài)為BLOCKED,才讓輔助線程退出同步。
        while (true){
            if(showThread.getState()==Thread.State.BLOCKED){
                print(showThread.getName(), Thread.State.BLOCKED);
                lockFlag=false;
                break;
            }
        }

        try {
            assistantThread.join();
            showThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //線程執(zhí)行完畢打印狀態(tài)。
        print(showThread.getName(), showThread.getState());
    }

    private static class SynTask implements Runnable {
        @Override
        public void run() {
            while (true) {
                //保證先進入同步范圍。
                if (order == 0) {
                    synchronized (lock) {
                        //啟動另一個同步
                        order=1;
                        //等待主線程讀取到線程阻塞狀態(tài),退出同步。
                        while (lockFlag) {
                            try {
                                Thread.sleep(10);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    break;
                }
            }
        }
    }

    private static class Task implements Runnable {
        @Override
        public void run() {
            while (true){
                //保證后進入同步范圍。
                if (order==1){
                    synchronized (lock){
                        print(Thread.currentThread().getName(),Thread.currentThread().getState());
                    }
                    break;
                }
            }
        }
    }
}

我們用order保證線程進入同步區(qū)的順序,用lockFlag保證只有在打印出顯示線程的被阻塞狀態(tài)后輔助線程才退出同步區(qū)。這樣無論如何執(zhí)行我們都會得到同樣的結(jié)果。

Thread-0:NEW
Thread-0:RUNNABLE
Thread-0:BLOCKED
Thread-0:RUNNABLE
Thread-0:TERMINATED
三、 新建--->可運行--->等待--->可運行--->被終止

這里我們展示兩種三種方法造成線程的等待狀態(tài)

Object.wait()

java.util.concurrent.locks.Locke.lock()

java.util.concurrent.locks.Condition.await()

其他方法如Thread.join()等大家可以參考示例代碼自己實現(xiàn)。

1. Object.wait()
/**
 * NEW->RUNNABLE->WAITING->RUNNABLE->TERMINATED
 */
public class ThreadStateNRWRT {
    //鎖
    private static final Object lock=new Object();

    public static void main(String[] args) {
        //展示線程
        Thread showThread = new Thread(new WaitTask());
        print(showThread.getName(), showThread.getState());
        showThread.start();
        print(showThread.getName(),showThread.getState());
        //循環(huán)讀取展示線程狀態(tài),直到讀到展示線程狀態(tài)為WAITING,才讓輔助線程喚醒等待線程。
        while (true){
            if(showThread.getState()==Thread.State.WAITING){
                print(showThread.getName(), Thread.State.WAITING);
                break;
            }
        }
        synchronized (lock){
            lock.notify();
        }


        try {
            showThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //線程執(zhí)行完畢打印狀態(tài)。
        print(showThread.getName(), showThread.getState());
    }


    private static class WaitTask implements Runnable {
        @Override
        public void run() {
            //等待
            synchronized (lock){
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            print(Thread.currentThread().getName(),Thread.currentThread().getState());
        }
    }
}
2. java.util.concurrent.locks.Locke.lock()
/**
 * NEW->RUNNABLE->WAITING->RUNNABLE->TERMINATED
 */
public class ThreadStateNRWRTLock {
    //鎖
    private  static Lock lock=new ReentrantLock();
    //鎖定標志
    private volatile static boolean lockFlag=true;
    //執(zhí)行順序
    private volatile static int order=0;

    public static void main(String[] args) {
        //展示線程
        Thread showThread = new Thread(new Task());
        print(showThread.getName(), showThread.getState());
        showThread.start();
        print(showThread.getName(), showThread.getState());
        //輔助線程,制造synchronized狀態(tài)。
        Thread assistantThread = new Thread(new SynTask());
        assistantThread.start();
        //循環(huán)讀取展示線程狀態(tài),直到讀到展示線程狀態(tài)為BLOCKED,才讓輔助線程退出同步。
        while (true){
            if(showThread.getState()==Thread.State.WAITING){
                print(showThread.getName(), Thread.State.WAITING);
                lockFlag=false;
                break;
            }
        }
        try {
            assistantThread.join();
            showThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //線程執(zhí)行完畢打印狀態(tài)。
        print(showThread.getName(), showThread.getState());
    }

    private static class SynTask implements Runnable {
        @Override
        public void run() {
            while (true) {
                //保證先進入同步范圍。
                if (order == 0) {
                    //加鎖
                    lock.lock();
                    try {
                        order=1;
                        while (lockFlag) {
                            try {
                                Thread.sleep(10);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }finally {
                        lock.unlock();
                    }
                    break;
                }
            }
        }
    }

    private static class Task implements Runnable {
        @Override
        public void run() {
            while (true){
                //保證后進入同步范圍。
                if (order==1){
                    lock.lock();
                    try{
                        print(Thread.currentThread().getName(),Thread.currentThread().getState());
                    }finally {
                        lock.unlock();
                    }
                    break;
                }
            }
        }
    }
}
3. java.util.concurrent.locks.Condition.await()
/**
 * NEW->RUNNABLE->WAITING->RUNNABLE->TERMINATED
 */
public class ThreadStateNRWRTCondition {
    //鎖
    private static Lock lock=new ReentrantLock();
    private static Condition condition=lock.newCondition();

    public static void main(String[] args) {
        //展示線程
        Thread showThread = new Thread(new WaitTask());
        print(showThread.getName(), showThread.getState());
        showThread.start();
        print(showThread.getName(),showThread.getState());
        //循環(huán)讀取展示線程狀態(tài),直到讀到展示線程狀態(tài)為WAITING,才讓輔助線程喚醒等待線程。
        while (true){
            if(showThread.getState()==Thread.State.WAITING){
                print(showThread.getName(), Thread.State.WAITING);
                break;
            }
        }

        lock.lock();
        try{
            condition.signal();
        }finally {
            lock.unlock();
        }


        try {
            showThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //線程執(zhí)行完畢打印狀態(tài)。
        print(showThread.getName(), showThread.getState());
    }


    private static class WaitTask implements Runnable {
        @Override
        public void run() {
            //等待
            lock.lock();
            try{
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }finally {
                lock.unlock();
            }
            print(Thread.currentThread().getName(),Thread.currentThread().getState());
        }
    }
}
4. 運行結(jié)果

三段代碼的運行結(jié)果都是:

Thread-0:NEW
Thread-0:RUNNABLE
Thread-0:WAITING
Thread-0:RUNNABLE
Thread-0:TERMINATED
四、新建--->可運行--->計時等待--->可運行--->被終止

我們展示兩個方法造成計時等待狀態(tài)

Object.wait(long timeout)

java.util.concurrent.locks.Condition.await(long time, TimeUnit unit)

其他方法如Thread.sleep(long millis),Thread.join(long millis)等大家可以自己實現(xiàn)。
感覺凡是有超時方法的方法都能讓線程狀態(tài)進入計時等待,但是這個沒有經(jīng)過驗證,所以只是一個猜想。

1. Object.wait(long timeout)
/**
 * NEW->RUNNABLE->TIMED_WAITING->RUNNABLE->TERMINATED
 */
public class ThreadStateNRTWRT {
    //鎖
    private static final Object lock=new Object();

    public static void main(String[] args) {
        //展示線程
        Thread showThread = new Thread(new WaitTask());
        print(showThread.getName(), showThread.getState());
        showThread.start();
        print(showThread.getName(),showThread.getState());
        //循環(huán)讀取展示線程狀態(tài),直到讀到展示線程狀態(tài)為TIMED_WAITING。
        while (true){
            if(showThread.getState()==Thread.State.TIMED_WAITING){
                print(showThread.getName(), Thread.State.TIMED_WAITING);
                break;
            }
        }

        try {
            showThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //線程執(zhí)行完畢打印狀態(tài)。
        print(showThread.getName(), showThread.getState());
    }


    private static class WaitTask implements Runnable {
        @Override
        public void run() {
            //等待
            synchronized (lock){
                try {
                    lock.wait(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            print(Thread.currentThread().getName(),Thread.currentThread().getState());
        }
    }
}
2. java.util.concurrent.locks.Condition.await(long time, TimeUnit unit)
/**
 * NEW->RUNNABLE->TIMED_WAITING->RUNNABLE->TERMINATED
 */
public class ThreadStateNRTWRTCondition {
    //鎖
    private static Lock lock=new ReentrantLock();
    private static Condition condition=lock.newCondition();

    public static void main(String[] args) {
        //展示線程
        Thread showThread = new Thread(new WaitTask());
        print(showThread.getName(), showThread.getState());
        showThread.start();
        print(showThread.getName(),showThread.getState());
        //循環(huán)讀取展示線程狀態(tài),直到讀到展示線程狀態(tài)為TIMED_WAITING。
        while (true){
            if(Thread.State.TIMED_WAITING==showThread.getState()){
                print(showThread.getName(), Thread.State.TIMED_WAITING);
                break;
            }
        }
        try {
            showThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //線程執(zhí)行完畢打印狀態(tài)。
        print(showThread.getName(), showThread.getState());
    }


    private static class WaitTask implements Runnable {
        @Override
        public void run() {
            //等待
            lock.lock();
           try{
                try {
                    condition.await(1,TimeUnit.MILLISECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }finally {
               lock.unlock();
           }
            print(Thread.currentThread().getName(),Thread.currentThread().getState());
        }
    }
}
3. 運行結(jié)果

兩段程序的運行結(jié)果相同:

Thread-0:NEW
Thread-0:RUNNABLE
Thread-0:TIMED_WAITING
Thread-0:RUNNABLE
Thread-0:TERMINATED
結(jié)語

至此,我們已經(jīng)介紹了線程狀態(tài)轉(zhuǎn)換的所有情況,了解線程狀態(tài)轉(zhuǎn)換對分析多線程代碼運行很幫助。希望本篇文章對大家今后工作有所助力。

參考

《Java核心技術(shù)+卷1》第九版

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/76926.html

相關(guān)文章

  • 一文讀懂 Java 中的原子類

    摘要:一無鎖方案并發(fā)包中的原子類都是基于無鎖方案實現(xiàn)的,相較于傳統(tǒng)的互斥鎖,無鎖并沒有加鎖解鎖線程切換的消耗,因此無鎖解決方案的性能更好,同時無鎖還能夠保證線程安全。線程首先讀取的值并加,如果此時有另一個線程更新了,則期望值和不相等,更新失敗。 一、無鎖方案 Java 并發(fā)包中的原子類都是基于無鎖方案實現(xiàn)的,相較于傳統(tǒng)的互斥鎖,無鎖并沒有加鎖、解鎖、線程切換的消耗,因此無鎖解決方案的性能更好...

    jas0n 評論0 收藏0
  • JVM(2)--一文讀懂垃圾回收

    摘要:對象存不進去,會又一次觸發(fā)垃圾回收。也就是說,它在進行垃圾回收時,必須暫停其他所有線程。我們來看一個名詞吞吐量。吞吐量運行用戶代碼時間運行用戶代碼時間垃圾收集時間。也就是說,收集器會嚴格控制吞吐量,至于這個吞吐量是多少,這個可以人為設(shè)置。 與其他語言相比,例如c/c++,我們都知道,java虛擬機對于程序中產(chǎn)生的垃圾,虛擬機是會自動幫我們進行清除管理的,而像c/c++這些語言平臺則需要...

    MRZYD 評論0 收藏0
  • 一文讀懂貝葉斯推理問題:MCMC方法和變分推斷

    摘要:本文將討論兩種可用于解決貝葉斯推理問題的主要方法基于采樣的馬爾可夫鏈蒙特卡羅,簡稱方法和基于近似的變分推理,簡稱方法。而貝葉斯推理則是從貝葉斯的角度產(chǎn)生統(tǒng)計推斷的過程。貝葉斯推理問題還可能會產(chǎn)生一些其他的計算困難。 全文共6415字,預(yù)計學(xué)習(xí)時長20分鐘或更長 showImg(https://segmentfault.com/img/bVbvFZZ?w=1280&h=853); 圖片來...

    msup 評論0 收藏0

發(fā)表評論

0條評論

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