1. 程式人生 > 程式設計 >Java執行緒生命週期和鎖的簡單使用

Java執行緒生命週期和鎖的簡單使用

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

執行緒生命週期

  • 初始狀態(New)

    New Thread之後,  

  • 就緒狀態(Ready)

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

  • 執行狀態(Runable)

    執行start之後,開始執行。  

  • 阻塞狀態(Blocked)

    在進入synchronized的臨界區或者Lock的臨界區,等待獲取監視器(monitor)鎖,執行緒會進入同步佇列(SynchronizedQueue)中。  

  • 等待狀態:(Waiting)

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

  • 等待超時狀態

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

  • 終止狀態

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

  • 配圖

鎖的幾個簡單方法

  • wait 和 notify/notifyAll

    解釋

    wait: 將執行緒狀態置位 '等待狀態',進入等待佇列等待。 notify/notifyAll:

    notify是隨機喚醒一個執行緒進入 '同步佇列',notifyAll是喚醒全部被監視器鎖wait的執行緒進入 '同步佇列',等待獲取監視器鎖後繼續執行。

    **提示:**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