1. 程式人生 > >java執行緒的使用詳解

java執行緒的使用詳解

Java執行緒具有五中基本狀態

新建狀態(New):當執行緒物件對建立後,即進入了新建狀態,如:Thread t = new MyThread();

就緒狀態(Runnable):當呼叫執行緒物件的start()方法(t.start();),執行緒即進入就緒狀態。處於就緒狀態的執行緒,只是說明此執行緒已經做好了準備,隨時等待CPU排程執行,並不是說執行了t.start()此執行緒立即就會執行;

執行狀態(Running):當CPU開始排程處於就緒狀態的執行緒時,此時執行緒才得以真正執行,即進入到執行狀態。注:就 緒狀態是進入到執行狀態的唯一入口,也就是說,執行緒要想進入執行狀態執行,首先必須處於就緒狀態中;

阻塞狀態(Blocked):處於執行狀態中的執行緒由於某種原因,暫時放棄對CPU的使用權,停止執行,此時進入阻塞狀態,直到其進入到就緒狀態,才 有機會再次被CPU呼叫以進入到執行狀態。根據阻塞產生的原因不同,阻塞狀態又可以分為三種:

1.等待阻塞:執行狀態中的執行緒執行wait()方法,使本執行緒進入到等待阻塞狀態;

2.同步阻塞 – 執行緒在獲取synchronized同步鎖失敗(因為鎖被其它執行緒所佔用),它會進入同步阻塞狀態;

3.其他阻塞 – 通過呼叫執行緒的sleep()或join()或發出了I/O請求時,執行緒會進入到阻塞狀態。當sleep()狀態超時、join()等待執行緒終止或者超時、或者I/O處理完畢時,執行緒重新轉入就緒狀態。

死亡狀態(Dead):執行緒執行完了或者因異常退出了run()方法,該執行緒結束生命週期。

執行緒中常用的方法

  1.start() : 執行緒呼叫該方法將啟動執行緒,使之從新建狀態進入就緒佇列排隊,一旦輪到它來享用CPU資源時,就可以脫離建立它的執行緒獨立開始自己的生命週期了。

  2.run(): Thread類的run()方法與Runnable介面中的run()方法的功能和作用相同,都用來定義執行緒物件被排程之後所執行的操作,都是系統自動呼叫而使用者程式不得引用的方法。

  3.sleep(int millsecond): 優先順序高的執行緒可以在它的run()方法中呼叫sleep方法來使自己放棄CPU資源,休眠一段時間。

  4.isAlive(): 執行緒處於“新建”狀態時,執行緒呼叫isAlive()方法返回false。線上程的run()方法結束之前,即沒有進入死亡狀態之前,執行緒呼叫isAlive()方法返回true.

  5.currentThread():該方法是Thread類中的類方法,可以用類名呼叫,該方法返回當前正在使用CPU資源的執行緒。

  6.interrupt() :一個佔有CPU資源的執行緒可以讓休眠的執行緒呼叫interrupt()方法“吵醒”自己,即導致休眠的執行緒發生InterruptedException異常,從而結束休眠,重新排隊等待CPU資源。
  
  7.yield( )方法:使當前執行緒從執行狀態(執行狀態)變為可執行態(就緒狀態)。cpu會從眾多的可執行態裡選擇,也就是說,當前也就是剛剛的那個執行緒還是有可能會被再次執行到的,並不是說一定會執行其他執行緒而該執行緒在下一次中不會執行到了。

8.join():方法使呼叫該方法的執行緒在此之前執行完畢,也就是等待該方法的執行緒執行完畢後再往下繼續執行。注意該方法也需要捕捉異常。

9.wait()和notify()、notifyAll():

這三個方法用於協調多個執行緒對共享資料的存取,所以必須在synchronized語句塊內使用。synchronized關鍵字用於保護共享資料,阻止其他執行緒對共享資料的存取,但是這樣程式的流程就很不靈活了,如何才能在當前執行緒還沒退出synchronized資料塊時讓其他執行緒也有機會訪問共享資料呢?此時就用這三個方法來靈活控制。

wait()方法使當前執行緒暫停執行並釋放物件鎖標示,讓其他執行緒可以進入synchronized資料塊,當前執行緒被放入物件等待池中。當呼叫notify()方法後,將從物件的等待池中移走一個任意的執行緒並放到鎖標誌等待池中,只有鎖標誌等待池中執行緒能夠獲取鎖標誌;如果鎖標誌等待池中沒有執行緒,則notify()不起作用。

notifyAll()則從物件等待池中移走所有等待那個物件的執行緒並放到鎖標誌等待池中。

10.run和start():

把需要處理的程式碼放到run()方法中,start()方法啟動執行緒將自動呼叫run()方法,這個由java的記憶體機制規定的。並且run()方法必需是public訪問許可權,返回值型別為void。

1.實現Runnable介面,並重寫該介面的run()方法

class MyRunnable implements Runnable {
    private int i = 0;
    @Override
    public void run() {
        for (i = 0; i < 100; i++) {
      System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}


----------
public class ThreadTest {

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 30) {
                Runnable myRunnable = new MyRunnable(); // 建立一個Runnable實現類的物件
                Thread thread1 = new Thread(myRunnable); // 將myRunnable作為Thread target建立新的執行緒
                Thread thread2 = new Thread(myRunnable);
                thread1.start(); // 呼叫start()方法使得執行緒進入就緒狀態
                thread2.start();
            }
        }
    }
}

2.繼承Thread類,重寫該類的run()方法

class MyThread extends Thread {

    private int i = 0;

    @Override
    public void run() {
        for (i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}


----------
public class ThreadTest {

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 30) {
                Thread myThread1 = new MyThread();     // 建立一個新的執行緒  myThread1  此執行緒進入新建狀態
                Thread myThread2 = new MyThread();     // 建立一個新的執行緒 myThread2 此執行緒進入新建狀態
                myThread1.start();                     // 呼叫start()方法使得執行緒進入就緒狀態
                myThread2.start();                     // 呼叫start()方法使得執行緒進入就緒狀態
            }
        }
    }
}

3.實現和繼承放在一起的對比

public class Test {

        public static void main(String[] args) {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + " " + i);
                if (i == 5) {
                    Runnable myRunnable = new MyRunnable();
                    Thread thread = new MyThread(myRunnable);
                    thread.start();
                }
            }
        }
    }

    class MyRunnable implements Runnable {
        private int i = 0;

        @Override
        public void run() {
            System.out.println("in MyRunnable run");
            for (i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + " " + i);
            }
        }
    }

    class MyThread extends Thread {

        private int i = 0;

        public MyThread(Runnable runnable){
            super(runnable);
        }

        @Override
        public void run() {
            System.out.println("in MyThread run");
            for (i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + " " + i);
            }
        }

}

執行結果 :Thread類本身也是實現了Runnable介面,而run()方法最先是在Runnable介面中定義的方法。

main 0
main 1
main 2
main 3
main 4
main 5
main 6
in MyThread run
Thread-0 0
Thread-0 1
Thread-0 2
Thread-0 3
Thread-0 4
Thread-0 5
Thread-0 6
Thread-0 7
Thread-0 8
Thread-0 9
main 7
main 8
main 9

一、同步(synchronized)和非同步(asynchronized)

public class SynAndAsynDemo {

    public static void main(String[] args) {

        final SynAndAsynDemo mo = new SynAndAsynDemo();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                mo.methodA();
            }
        },"t1");

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                mo.methodB();
            }
        },"t2");

        t1.start();
        t2.start();
    }

    // 方法A
    public synchronized void methodA(){
        try {
            System.out.println(Thread.currentThread().getName());
            // 休眠4秒
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    // 方法B
    public void methodB(){
        System.out.println(Thread.currentThread().getName());
    }

}
package com.ietree.multithread.sync;

/**
 * 多執行緒之物件同步鎖和非同步鎖Demo
 *
 * @author ietree
 */
public class SynAndAsynDemo {

    public static void main(String[] args) {

        final SynAndAsynDemo mo = new SynAndAsynDemo();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                mo.methodA();
            }
        },"t1");

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                mo.methodB();
            }
        },"t2");

        t1.start();
        t2.start();
    }

    // 方法A
    public synchronized void methodA(){
        try {
            System.out.println(Thread.currentThread().getName());
            // 休眠4秒
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    // 方法B
    public synchronized void methodB(){
        System.out.println(Thread.currentThread().getName());
    }

}