Java線程生命週期和鎖的簡單使用

本文介紹了java線程的生命週期,Synchronized的幾個方法簡單的使用。java

線程生命週期

  • 初始狀態(New)

    New Thread以後,  git

  • 就緒狀態(Ready)

    表示獲取到了Cpu的執行時間片,也就是cpu的執行權,等待開始執行。  github

  • 運行狀態(Runable)

    執行start以後,開始運行。  bash

  • 阻塞狀態(Blocked)

    在進入synchronized的臨界區或者Lock的臨界區,等待獲取監視器(monitor)鎖,線程會進入同步隊列(SynchronizedQueue)中。  ide

  • 等待狀態:(Waiting)

    在執行await(),wait(),jion(),LockSupport.park()方法進入等待狀態;  spa

  • 等待超時狀態

    在執行Object.await(time), Object.wait(time), Object.sellp(time), LockSupport.parkUntil,lockSupport.parkNanos 進入等待超時狀態。  線程

  • 終止狀態

    線程執行完畢或者執行了Thread.interrupt() / Thread.stop(),不建議使用的Thread.stop() 由於 Thread.stop是直接強行結束,不會釋放資源code

  • 配圖

鎖的幾個簡單方法

  • wait 和 notify/notifyAll

    解釋

    wait: 將線程狀態置位 '等待狀態',進入等待隊列等待。 notify/notifyAll: notify是隨機喚醒一個線程進入 '同步隊列',notifyAll是喚醒所有被監視器鎖wait的線程進入 '同步隊列',等待獲取監視器鎖後繼續執行。cdn

    **提示:**wait,notify/notifyAll都須要在獲取到監視器所(monitor)後才能夠進行操做。對象

    代碼
    public class WaitAndNotifyTest {
    
        private static Object obj = new Object();
    
        public static void main(String[] args) {
            // 建立線程 thread1
            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName() + " begin wait...");
                        synchronized (obj) {
                            obj.wait();
                        }
                        System.out.println(Thread.currentThread().getName() + " end wait...");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, "thread1");
    
            // 建立線程 thread2
            Thread thread2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName() + " begin wait...");
                        synchronized (obj) {
                            obj.wait();
                        }
                        System.out.println(Thread.currentThread().getName() + " end wait...");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, "thread2");
    
    
    
            // 啓動
            thread1.start();
            thread2.start();
    
            try {
                // 睡眠一秒
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            // 下面咱們加上 obj.notify() 就會先輸出 begin wait 而後sellp 10秒,執行obj.notify() 喚醒 thread1 線程 , 輸出end wait
            // obj 上可能會存在wait 多個線程, notify喚醒是隨機的,不必定能喚醒哪個線程
            // 若是調用 notify 的線程未獲取 對象鎖,在調用 notify 的時候會拋出 java.lang.IllegalMonitorStateException 異常
            synchronized (obj) {
                // 喚醒 使用呢 obj 調用 wait 方法的其中一個線程 (隨機)
                obj.notify();
                // 喚醒 使用呢 obj 調用 wait 方法的全部線程
                obj.notifyAll();
            }
        }
    }
    複製代碼
    執行結果:
    thread2   begin wait...
    thread1   begin wait...
    thread1   end wait...
    thread2   end wait...
    複製代碼
  • await,signal/signalAll

    解釋

    await,signal/signalAll方法是Lock Condition的方法,語義和Object的wait,notify/notifyAll是徹底相同的。

    代碼
    /** * @Auther: lantao * @Date: 2019-04-15 14:49 * @Company: * @maill: * @Description: Condition 條件 有 singal signalAll 和 await 方法 和Object 的 notify notifyAll 和 wait 是一個意思一樣會釋放鎖 執行singal和notify的時候也須要在等待獲取鎖 */
            public class LockCondition {
    
                public static ReentrantLock lock = new ReentrantLock();
    
                public static Condition a = lock.newCondition();
    
                public static void main(String[] args) throws InterruptedException {
                    Runnable runnable = () -> {
                        try {
                            lock.lock();
                            System.out.println(Thread.currentThread().getName());
                            System.out.println("1");
                            a.await();
    
                            System.out.println(Thread.currentThread().getName() + "被喚醒了");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }finally {
                            lock.unlock();
                        }
                    };
    
                    Runnable runnable1 = () -> {
                        try {
                            lock.lock();
                            System.out.println("線程" +Thread.currentThread().getName() + "開始執行sinal");
                            a.signalAll();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }finally {
                            lock.unlock();
                        }
                    };
    
                    new Thread(runnable,"Thread1").start();
                    new Thread(runnable,"Thread2").start();
                    Thread.sleep(100);
                    new Thread(runnable1,"Thread3").start();
                }
            }
    複製代碼
    執行結果:
    Thread1
    Thread2
    線程Thread3開始執行sinal
    Thread1被喚醒了
    Thread2被喚醒了
    複製代碼
  • Join 和 Join(time)

    解釋

    等待調用Join的線程執行完成後再繼續執行,或者等待時間超過了超時時間繼續執行

    代碼
    /** * @Auther: lantao * @Date: * @Company: * @maill: * @Description: Join 核心是等待指定線程運行完後再繼續運行 Join(time) 就是等待線程執行的一個超時時間 超過了就繼續執行了 */
            public class JoinTest {
                public static void main(String[] args) throws InterruptedException {
                    Thread thread1 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            System.out.println("1");
                            try {
                                Thread.sleep(2000L);
                                System.out.println("正常完成");
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            System.out.println("2");
                        }
                    });
    
                    thread1.start();
    
                    // 執行 jion 等待線程 thread1 執行完後再繼續執行
                    thread1.join();
    // thread1.join(1000);
    
                    // 這樣最終執行的順序是 1 2 3 若是不增長 thread1.join() 結果多是 312 也多是 132
                    // Join 核心是等待指定線程運行完後再繼續運行
                    System.out.println("3");
                }
            }
    複製代碼
    執行結果:
    1
    正常完成
    2
    3
    複製代碼
  • yield

    解釋

    yeid 方法的核心是讓出 cpu 時間片 ,也就是cpu執行權,線程會直接進入就緒狀態,線程調度器會從線程就緒隊列裏獲取一個線程優先級最高的線程來執行,固然也有可能直接會去到剛剛讓出cpu執行權的線程,繼續執行yield 後續的代碼。

    代碼
    /** * @Auther: lantao * @Date: 2019-03-25 17:20 * @Company: * @maill: * @Description: */
            public class YieldTest {
    
                private static Object obj = new Object();
    
    
                public static void main(String[] args) {
                    Thread thread1 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            for (int i = 0; i <= 5; i++) {
    
                                if (0 / 5 == i) {
                                    System.out.println(Thread.currentThread().getName() + " 開始執行 yield ");
                                    Thread.yield();
                                    System.out.println("trhead1");
                                }
                            }
                        }
                    }, "thread1");
                    Thread thread2 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            for (int i = 0; i <= 5; i++) {
                                if (0 / 5 == i) {
                                    System.out.println(Thread.currentThread().getName() + " 開始執行 yield ");
                                    Thread.yield();
                                    System.out.println("trhead2");
                                }
                            }
                        }
                    }, "thread2");
                    Thread thread3 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            for (int i = 0; i <= 5; i++) {
                                if (0 / 5 == i) {
                                    System.out.println(Thread.currentThread().getName() + " 開始執行 yield ");
                                    Thread.yield();
                                    System.out.println("trhead3");
                                }
                            }
    
                        }
                    }, "thread3");
    
                    // 執行三個線程, 正常當運行到yield 是 就會讓出cpu執行權,線程到 就緒狀態,線程調度器會從 線程就緒隊列裏獲取一個線程優先級最高的線程來執行,
                    // 固然也有可能直接會去到剛剛讓出cpu的線程,繼續執行yield 後續的代碼
                    thread1.start();
                    thread3.start();
                    thread2.start();
    
                }
            }
    複製代碼
    執行結果:
    
    thread1   開始執行 yield
    thread2   開始執行 yield
    thread3   開始執行 yield
            trhead2
    trhead1
    trhead3
    複製代碼
  • interrupt 和 stop

    解釋

    interrupt和stop都表明中斷線程,區別是 interrupt 會釋放資源而stop不會,interrupt也不會立馬就中斷;說道interrupt就得說一下isInterrupted方法,他是判斷線程中斷標誌的,若是線程A執行了線程B的interrupt方法,線程B在本身的線程中也可使用 isInterrupted 方法判斷本身的中斷標誌。   注意:在使用 interrupt方法時,若是線程在sleep wait wait(time)狀態, 拋出InterruptedException異常後會清除 isInterrupted 方法獲取的中斷標誌位,反之則不會

    代碼
    /** * @Auther: lantao * @Date: 2019-04-17 17:18 * @Company: * @maill: * @Description: 在使用 interrupt方法是,若是線程咋sleep wait wait(time) 在拋出InterruptedException異常後會 清除 isInterrupted 方法獲取的標誌位 其餘則不會 */
            public class InterruptTest {
                public static void main(String[] args) throws InterruptedException {
                    Thread thread1 = new Thread(() -> {
                        while (true) {}
                    }, "循環線程");
    
                    Thread thread2 = new Thread(() -> {
                        while (true) {
                            try {
                                Thread.sleep(200);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }, "睡眠線程");
    
                    Thread thread3 = new Thread(() -> {
                        Object o = new Object();
                        while (true) {
                            synchronized (o){
                                try {
                                    o.wait();
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }, "等待線程");
    
                    thread1.start();
                    thread2.start();
                    thread3.start();
                    Thread.sleep(500);
    
                    thread1.interrupt();
                    thread2.interrupt();
                    thread3.interrupt();
                    Thread.sleep(500);
                    System.out.println("循環線程isInteryupt is " + thread1.isInterrupted());
                    System.out.println("睡眠線程isInteryupt is " + thread2.isInterrupted());
                    System.out.println("等待線程isInteryupt is " + thread3.isInterrupted());
    
    
                }
            }
    複製代碼
    執行結果:
    
    java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at com.com.concurrenncy.InterruptTest.lambda$main$1(InterruptTest.java:20)
    at java.lang.Thread.run(Thread.java:748)
    java.lang.InterruptedException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at com.com.concurrenncy.InterruptTest.lambda$main$2(InterruptTest.java:32)
    at java.lang.Thread.run(Thread.java:748)
    循環線程isInteryupt is true
    睡眠線程isInteryupt is false
    等待線程isInteryupt is false
    複製代碼

    博客地址:lantaoblog.site

相關文章
相關標籤/搜索