java 線程 run和start方法,線程生命週期及join和yield方法,守護線程

  • 線程 run和start方法說明

run方法:其實是Runnable接口方法,只是個接口規範,業務邏輯都寫在這個方法中(線程結束判斷以及具體業務邏輯)

start方法:Thread 線程類封裝的規範,一個線程實例只有調用了start方法,才能夠開啓新線程執行run。否則只調用run方法,實際並沒有開啓新的線程。start方法只能夠調用一次,多次調用會報出異常 IllegalThreadStateException。start其實並不會開啓線程,內部調用start0()方法纔會真正的開啓線程。

  • 線程生命週期

從這個圖中可以看到線程的狀態流轉,這裏主要介紹線程的join和yield方法,後續會詳細講解notify和wait方法。

join 方法(獲取CPU執行權):a線程調用b線程的join方法,就是把當前CPU執行權交給線程b,當執行完b線程後,才執行線程a。一般會用來控制多線程按照順序執行(本來多線程是並行執行的),通過join方法可以控制每個線程的執行順序。

yield方法(奉獻出CPU執行權):調用a線程的yield方法,線程a就會進入就緒狀態,CPU會從就緒線程集合中隨機(有優先級)拿一個線程執行。當然拿到的這個線程也可能還是a線程,yield方法跟鎖沒有任何關係,並不是說釋放鎖。

  • join方法案例,多任務按照順序執行
  • 無序
import java.util.Random;

public class xu02 {
    private static class BuyTicket extends Thread{
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"--正在購票--------");
            try {
                //模擬每個人購票時間不確定
                Thread.sleep(new Random().nextInt(50));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"--購票完成--------");
        }
    }
    public static void main(String[] args) {
        //創建3個人排隊購票
        BuyTicket bird=new BuyTicket();
        bird.setName("bird");
        BuyTicket dog=new BuyTicket();
        dog.setName("dog");
        BuyTicket cat=new BuyTicket();
        cat.setName("cat");
        //1:無序購票(未排隊),這裏並不能夠確定誰先買完票
        cat.start();
        dog.start();
        bird.start();
    }
}
  • 指定順序購票
package com.hongying.multithread;

import java.util.Random;

public class xu02 {
    private static class BuyTicket extends Thread{
        private Thread preThread;//排在他前面的人
        public BuyTicket(Thread pre){
            this.preThread=pre;
        }
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"--正在購票--------");
            //做個判斷,只有排在前面的人完成購票了才允許購票
            if(preThread!=null){
                try {
                    preThread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            try {
                //模擬每個人購票時間不確定
                Thread.sleep(new Random().nextInt(50));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"--購票完成--------");
        }
    }
    public static void main(String[] args) {
        //創建3個人排隊購票
        BuyTicket cat=new BuyTicket(null);//第一個位置
        cat.setName("cat");
        BuyTicket dog=new BuyTicket(cat);//第二個位置
        dog.setName("dog");
        BuyTicket bird=new BuyTicket(dog);//最後購票+
        bird.setName("bird");
        //有序購票,bird->dog->cat
        bird.start();//儘管bird第一個開啓購票,但是也會是最後一個結束購票
        dog.start();
        cat.start();
        /*運行結果:
        * dog--正在購票--------
            *bird--正在購票--------
            cat--正在購票--------
            cat--購票完成--------
            dog--購票完成--------
            bird--購票完成--------
            */
    }
}
  • 守護線程和資源釋放

守護線程:設置當前線程的setDaemon(true),默認創建線程是非守護線程;守護線程時,當主線程結束後,守護線程也跟着死亡。

資源釋放:1、Object的finalize()方法,可以寫資源釋放,但是不推薦,有時不會執行。比如線程直接stop()

2、推薦 try-finally 資源釋放,但是有個特列是當前線程是守護線程,主線程結束後,子線程如果不是interrupt 標誌結束,子線程死亡有時不會調用finally 代碼塊。所以推薦不管是否是守護線程,線程結束都要使用 interrupt 標誌 結束線程

代碼案例:

package other.multithread;

/**
 * @ClassName DaemonTest
 * @Description des
 * @Author zyk
 * @Date 2019/9/26
 * @Version 1.0
 **/
public class DaemonTest {
    private static class DaemonThread extends Thread {
        @Override
        public void run() {
            try {
                while (true) {
                    System.out.println("-----------working...------------");
                    if (Thread.currentThread().isInterrupted()) {
                        System.out.println("============線程結束==================");
                        break;
                    }
                }
            } finally {
                //通過finally 進行資源釋放;如果是守護線程,線程結束finally有時還是不會執行
                System.out.println("=============finally-資源釋放執行=============");
            }

        }

        @Override
        protected void finalize() throws Throwable {
            //Object finalize 方法,可以完成資源釋放,但是線程停止則有可能不會調到finalize()
            System.out.println("=============finalize-資源釋放執行=============");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        DaemonThread daemonThread = new DaemonThread();
        //設置守護進程後,開啓線程的線程關閉後,守護線程也會結束;默認非守護線程
        daemonThread.setDaemon(true);
        daemonThread.start();

        Thread.sleep(20);
        //通過標誌位暫停線程,如果不interrupt(),當前線程是守護線程,主線程結束子線程也跟着結束,此時finally中 資源釋放有時就不會執行
        //daemonThread.interrupt();

        System.out.println("===========main線程結束=============");
    }
}

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章