併發-2-Thread和Runnable的API

Coding挖掘機發表於2018-10-17

建立執行緒的兩種方式:

1.繼承Thread,重寫run方法,使用start()使用執行緒 

2.將Runnable作為Thread的構造引數
複製程式碼
public class ThreadCreate {
    public static void main(String[] args) {
        System.out.println("主執行緒ID:" + Thread.currentThread().getId());

        /**
         * 第一種建立執行緒的方式
         */
        Thread firstMethod2CreateThread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("子執行緒ID:" + Thread.currentThread().getId());
            }
        });
        firstMethod2CreateThread.start();

        /**
         * 第二種建立執行緒的方式
         */
        class SecondMethod2CreateThread extends Thread {
            @Override
            public void run() {
                System.out.println("子執行緒ID:" + Thread.currentThread().getId());
            }
        }
        SecondMethod2CreateThread secondMethod2CreateThread = new SecondMethod2CreateThread();
        secondMethod2CreateThread.start();
    }
}
複製程式碼

Thread類詳解:

JAVA中多執行緒的核心是Thread,Thread翻譯為執行緒,執行緒有以下幾種狀態,接下來我會按照Thread類中的方法來逐一講解。
複製程式碼

併發-2-Thread和Runnable的API

1.Thread t = new Thread()僅僅只是建立了執行緒,並沒有為執行緒分配任何資源
2.start()方法用來啟動執行緒,為相應地執行緒分配資源,分配到資源才能參與到競爭CPU的過程中 run():當start()啟動一個執行緒後,執行緒一直等待直到獲得了CPU執行時間,就進入run方法體

3.sleep()讓執行緒休眠,主動讓出CPU,但是不會釋放鎖,休眠時間滿後,不一定立即得到執行,還需要重新參與競爭排隊

public class ThreadSleep {

    private int i = 0;
    public Object lock = new Object();

    public static void main(String[] args) {
        ThreadSleep mh = new ThreadSleep();
        ThreadTest tt = mh.new ThreadTest();
        ThreadTest tt2 = mh.new ThreadTest();
        tt.start();
        tt2.start();
    }

    class ThreadTest extends Thread {
        @Override
        public void run() {
            //使用的鎖為Object lock = new Object(); 而不是方法所在的類的內建monitor
            synchronized (lock) {
                i++;
                System.out.println("i:" + i);
                try {
                    System.out.println("執行緒i:" + Thread.currentThread().getId() + "睡眠開始");
                    long startTime = System.currentTimeMillis();
                    Thread.currentThread().sleep(1000);
                    long endTime = System.currentTimeMillis();
                    System.out.println("執行緒i:" + Thread.currentThread().getId() + "睡眠時間:" + (endTime - startTime));
                } catch (Exception e) {
                } finally {
                    System.out.println("執行緒i:" + Thread.currentThread().getId() + "睡眠結束");
                }
                i++;
                System.out.println("i:" + i);
            }
        }
    }
}
複製程式碼

輸出:

i:1
執行緒i:9睡眠開始
執行緒i:9睡眠時間:1005
執行緒i:9睡眠結束
i:2
i:3
執行緒i:10睡眠開始
執行緒i:10睡眠時間:1004
執行緒i:10睡眠結束
i:4
複製程式碼

4.yield()使執行緒讓出CPU去執行相同優先順序的其他程式,但是不會釋放鎖,(內部還是sleep)執行yield()之後該執行緒直接進入就緒狀態再次參與競爭,生產中很少使用。

5.A執行緒的run()中呼叫了B執行緒的join(),則A執行緒等待B執行緒執行完之後,再繼續執行,實際上呼叫了Object類中的wait()方法,會釋放鎖

public class ThreadJoin {

    public static void main(String[] args) throws IOException {
        System.out.println("進入執行緒"+Thread.currentThread().getName());
        ThreadJoin test = new ThreadJoin();
        MyThread thread1 = test.new MyThread();
        thread1.start();
        try {
            System.out.println("執行緒"+Thread.currentThread().getName()+"等待");
            thread1.join();
            System.out.println("執行緒"+Thread.currentThread().getName()+"繼續執行");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    class MyThread extends Thread{
        @Override
        public void run() {
            System.out.println("進入執行緒"+Thread.currentThread().getName());
            try {
                Thread.currentThread().sleep(5000);
            } catch (InterruptedException e) {
                // TODO: handle exception
            }
            System.out.println("執行緒"+Thread.currentThread().getName()+"執行完畢");
        }
    }
}
複製程式碼

輸出:

進入執行緒main
執行緒main等待
進入執行緒Thread-0
執行緒Thread-0執行完畢
執行緒main繼續執行
複製程式碼

6.interrupt()使得處於阻塞狀態的執行緒丟擲一個異常,也就是說,它可以中斷並且只能中斷一個處於阻塞狀態的執行緒

public class ThreadInterrput {

    public static void main(String[] args) {
        ThreadInterrput mh = new ThreadInterrput();
        ThreadTest tt = mh.new ThreadTest();
        tt.start();
        try {
            Thread.currentThread().sleep(2000);
        } catch (InterruptedException e) {
        }
        tt.interrupt();
    }

    class ThreadTest extends Thread {
        @Override
        public void run() {
            try {
                System.out.println("子執行緒睡眠開始");
                Thread.currentThread().sleep(10000);
                System.out.println("子執行緒睡眠結束");
            } catch (InterruptedException e) {
                System.out.println("子執行緒獲取到中斷");
            }
            System.out.println("run執行完畢");
        }
    }
}
複製程式碼

輸出:

子執行緒睡眠開始
子執行緒獲取到中斷
run執行完畢
複製程式碼

7.開發中一般不使用interrupt()而在類中增加isStop屬性來標誌是否結束while迴圈

class MyThread extends Thread{
        private volatile boolean isStop = false;
        @Override
        public void run() {
            int i = 0;
            while(!isStop){
                i++;
            }
        }
         
        public void setStop(boolean stop){
            this.isStop = stop;
        }
    }
複製程式碼

這樣一來便可線上程外通過呼叫setStop方法來終止while迴圈。

相關文章