線程狀態(tài)

線程狀態(tài)

線程狀態(tài)
  1. 新建狀態(tài)

    new出一個線程,線程還沒有開始運行,當線程處于新建狀態(tài)時,程序還沒有運行線程中的代碼。

  2. 就緒狀態(tài)
    當線程對象調(diào)用start()方法即啟動了線程,start()方法創(chuàng)建線程運行的系統(tǒng)資源,并調(diào)度線程運行run()方法。當start()方法返回后,線程就處于就緒狀態(tài)。

    處于就緒狀態(tài)的線程并不一定立即運行run()方法,線程還必須同其他線程競爭CPU時間,只有獲得CPU時間才可以運行線程。對處于就緒狀態(tài)的線程是由Java運行時系統(tǒng)的線程調(diào)度程序(thread scheduler)來調(diào)度的。

  3. 運行狀態(tài)

    當線程獲得CPU時間后,它才進入運行狀態(tài),真正開始執(zhí)行run()方法。

  4. 阻塞狀態(tài)

    當一個線程試圖獲取一個內(nèi)部的對象鎖(非java.util.concurrent庫中的鎖),而該鎖被其他線程持有,則該線程進入阻塞狀態(tài)。

  5. 等待狀態(tài)
    處于等待狀態(tài)的線程正在等待另一個線程執(zhí)行特定操作,例如Object.wait()等待一個線程notify,Thread.join()等待另一個線程執(zhí)行結(jié)束。

  6. 死亡狀態(tài)

    有兩個原因會導(dǎo)致線程死亡:

    (1)run方法正常退出而自然死亡,

    (2)一個未捕獲的異常終止了run方法而使線程猝死。

線程調(diào)度

線程休眠

線程睡眠是線程主動讓出CPU讓其他線程執(zhí)行,線程從運行狀態(tài)切換為阻塞狀態(tài),線程休眠是其他線程執(zhí)行的有效方法,但是休眠時間到休眠線程未必執(zhí)行,它的執(zhí)行依靠CPU的調(diào)度。但是線程在休眠的時候仍然占有鎖,而且sleep()是靜態(tài)方法,只能控制當前正在運行的線程。

/**
 *  睡眠
 *  一個計數(shù)器,計數(shù)到 100,在每個數(shù)字之間暫停 1 秒,每隔 10 個數(shù)字輸出一個字符串
 */

public class ThreadSleep {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            public void run() {
                for(int i = 0; i < 100; i++){
                    if((i) % 10 ==0 ){
                        System.out.println("************");
                    }
                    try {
                        Thread.sleep(1);
                        System.out.println("i的值是:" + i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
}

線程讓步

運行狀態(tài)的線程讓出CPU資源,但是然給誰不知道,僅僅是讓出,也有可能是自己,線程從運行狀態(tài)切換為阻塞狀態(tài)。

public class ThreadYield {
    public static void main(String[] args) {
        Thread t1 = new MyThread1();
        Thread t2 = new Thread(new MyRunnable());
        
        t2.start();
        t1.start();
    }
    static class MyThread1 extends Thread {
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println("線程1第" + i + "次執(zhí)行!");
            }
        }
    }

    static class MyRunnable implements Runnable {
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println("線程2第" + i + "次執(zhí)行!");
                Thread.yield();
            }
        }
    }

}
//執(zhí)行結(jié)果(可以看出線程線程1執(zhí)行完后線程1開始執(zhí)行)
線程2第0次執(zhí)行!
線程1第0次執(zhí)行!
線程1第1次執(zhí)行!
線程1第2次執(zhí)行!
線程1第3次執(zhí)行!
線程1第4次執(zhí)行!
線程1第5次執(zhí)行!
線程1第6次執(zhí)行!
線程1第7次執(zhí)行!
線程1第8次執(zhí)行!
線程1第9次執(zhí)行!
線程2第1次執(zhí)行!
線程2第2次執(zhí)行!
線程2第3次執(zhí)行!
線程2第4次執(zhí)行!
線程2第5次執(zhí)行!
線程2第6次執(zhí)行!
線程2第7次執(zhí)行!
線程2第8次執(zhí)行!
線程2第9次執(zhí)行!

線程合并

現(xiàn)在有線程A、線程B,線程合并是將線程A、B合二為一,線程A先執(zhí)行,然后調(diào)用join方法,則線程B開始執(zhí)行,等B執(zhí)行完成后A再接著上次繼續(xù)執(zhí)行。應(yīng)用場景是當一個線程必須等待另一個線程執(zhí)行完畢才能執(zhí)行時可以使用join方法。

public class ThreadJoin extends Thread {
    public static void main(String[] args) {
        Thread t1 = new MyThread2();
        t1.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("主線程第" + i + "次執(zhí)行!");
            if (i > 2) try {
            //t1 線程合并到主線程中,主線程停止執(zhí)行過程,轉(zhuǎn)而執(zhí)行 t1 線程, 直到 t1 執(zhí)行完畢后繼續(xù)。
                t1.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


class MyThread2 extends Thread {
    public void run() {
        for (int i = 0; i < 4; i++) {
            System.out.println("線程 1 第" + i + "次執(zhí)行!");
        }
    }
}
//執(zhí)行結(jié)果
主線程第0次執(zhí)行!
主線程第1次執(zhí)行!
主線程第2次執(zhí)行!
主線程第3次執(zhí)行!
線程 1 第0次執(zhí)行!
線程 1 第1次執(zhí)行!
線程 1 第2次執(zhí)行!
線程 1 第3次執(zhí)行!
主線程第4次執(zhí)行!
主線程第5次執(zhí)行!
主線程第6次執(zhí)行!
主線程第7次執(zhí)行!
主線程第8次執(zhí)行!
主線程第9次執(zhí)行!

線程守候

守護線程在沒有用戶線程可服務(wù)時自動離開,在Java虛擬機中當正在運行的線程都是守護線程時,Java虛擬機退出。調(diào)用線程對象的方法setDaemon(true),則可以將其設(shè)置為守護線程,該方法必須在線程調(diào)用前執(zhí)行。

public class ThreadDaemon {
    public static void main(String[] args) {
        Thread t1 = new MyCommon();
        Thread t2 = new MyDaemon();
        t2.setDaemon(true);
        t1.start();
        t2.start();

    }
}

class MyCommon extends Thread {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("線程MyCommon第" + i + "次執(zhí)行!");
            try {
                Thread.sleep(7);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


class MyDaemon extends Thread {
    public void run() {
        for (int i = 0; i < 400; i++) {
            System.out.println("線程  MyDaemon  第" + i + "次執(zhí)行!");
            try {
                Thread.sleep(7);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}
//執(zhí)行結(jié)果(MyDaemon線程還沒有執(zhí)行完成便退出)
線程MyCommon第0次執(zhí)行!
線程  MyDaemon  第0次執(zhí)行!
線程  MyDaemon  第1次執(zhí)行!
線程MyCommon第1次執(zhí)行!
線程MyCommon第2次執(zhí)行!
線程  MyDaemon  第2次執(zhí)行!
線程MyCommon第3次執(zhí)行!
線程  MyDaemon  第3次執(zhí)行!
線程MyCommon第4次執(zhí)行!
線程  MyDaemon  第4次執(zhí)行!
線程  MyDaemon  第5次執(zhí)行!

線程優(yōu)先級

線程的有限執(zhí)行順序,優(yōu)先級1~10,數(shù)值越大優(yōu)先級越高。在一個線程中開啟另外一個新線程,則新開線程稱為該線程的子線程,子線程初始優(yōu)先級與父線程相同。

注意:線程的優(yōu)先級仍然無法保障線程的執(zhí)行次序。只不過,優(yōu)先級高的線程獲取CPU資源的概率較大,優(yōu)先級低的并非沒機會執(zhí)行。

public class ThreadPriority {
    public static void main(String[] args) {
        Thread threadA = new Thread(new ThreadA());
        Thread threadB = new Thread(new ThreadB());
        threadA.setPriority(10);
        threadB.setPriority(1);

        threadB.start();
        threadA.start();
    }

}

class ThreadA extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("    A線程第" + i + "次執(zhí)行");
        }
    }
}

class ThreadB extends Thread {
    @Override
    public void run() {
        for (int j = 0; j < 10; j++) {
            System.out.println("B線程第" + j + "次執(zhí)行");
        }
    }
}
//執(zhí)行結(jié)果
B線程第0次執(zhí)行
B線程第1次執(zhí)行
    A線程第0次執(zhí)行
B線程第2次執(zhí)行
    A線程第1次執(zhí)行
    A線程第2次執(zhí)行
B線程第3次執(zhí)行
B線程第4次執(zhí)行
B線程第5次執(zhí)行
B線程第6次執(zhí)行
B線程第7次執(zhí)行
B線程第8次執(zhí)行
B線程第9次執(zhí)行
    A線程第3次執(zhí)行

問題

  1. 為什么synchronized等到獲取鎖是阻塞,而ReentrantLock是阻塞。

代碼驗證:

public class StatusDemo {
    static Object lock = new Object();

    public static void read() {
        synchronized (lock) {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("讀數(shù)據(jù)");
        }
    }

    public static void write() {
        synchronized (lock) {
            System.out.println("寫數(shù)據(jù)");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                StatusDemo.read();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                StatusDemo.write();
            }
        }).start();

    }
}
public class StatusDemo {
      static  ReentrantLock lock = new ReentrantLock();

    public static void read() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName()+"讀數(shù)據(jù)");
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void write() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName()+"寫數(shù)據(jù)");
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                StatusDemo1.read();
            }
        }).start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                StatusDemo1.write();
            }
        }).start();

    }
}

為什么ReentrantLock是阻塞呢,看ReentrantLock的源碼你會發(fā)現(xiàn),其實ReentrantLock是AQS實現(xiàn)的,而AQS中使用了park()和unpark().

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,619評論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,155評論 3 425
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,635評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,539評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,255評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,646評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,655評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,838評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,399評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,146評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,338評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,893評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,565評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,983評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,257評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,059評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,296評論 2 376