Java線程基礎

線程具備五中基本狀態

新建狀態(New):當線程對象對建立後,即進入了新建狀態,如:Thread t = new MyThread();html

就緒狀態(Runnable):當調用線程對象的start()方法(t.start();),線程即進入就緒狀態。處於就緒狀態的線程,只是說明此線程已經作好了準備,隨時等待CPU調度執行,並非說執行了t.start()此線程當即就會執行;java

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

阻塞狀態(Blocked):處於運行狀態中的線程因爲某種緣由,暫時放棄對CPU的使用權,中止執行,此時進入阻塞狀態,直到其進入到就緒狀態,才 有機會再次被CPU調用以進入到運行狀態。根據阻塞產生的緣由不一樣,阻塞狀態又能夠分爲三種:函數

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

2.同步阻塞 -- 線程在獲取synchronized同步鎖失敗(由於鎖被其它線程所佔用),它會進入同步阻塞狀態;spa

3.其餘阻塞 -- 經過調用線程的sleep()或join()或發出了I/O請求時,線程會進入到阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程從新轉入就緒狀態。線程

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

 

實現方式:

1.繼承Thread類,重寫run方法
2.實現Runnable接口,重寫run方法,實現Runnable接口的實現類的實例對象做爲Thread構造函數的target
3.經過Callable和FutureTask建立線程

1.繼承Thread類,重寫run方法

public class MyThread extends Thread {

    @Override
    public void run() {
        System.out.println("MyThread:run");
    }

    public static void main(String[] args) {
        Thread thread = new MyThread();
        thread.start();
    }
}

2.實現Runnable接口,重寫run方法,實現Runnable接口的實現類的實例對象做爲Thread構造函數的target

public class MyRunnable implements Runnable {

    @Override
    public void run() {
        System.out.println("MyRunnable:run");
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start();
    }
}

3.經過Callable和FutureTask建立線程

public class MyCallable implements Callable<String> {
    @Override
    public String call() {
        try {
            System.out.println("MyCallable:run");
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "MyCallable:call";
    }

    public static void main(String[] args) {
        MyCallable myCallable = new MyCallable();
        FutureTask<String> task = new FutureTask<String>(myCallable);
        Thread thread = new Thread(task);
        thread.start();
        try {
            System.out.println(task.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

task.get()的時候阻塞,直到會調用task的線程執行完返回後才繼續code

 

線程的操做

sleep,yield,wait,join函數的區別

sleep:線程暫停執行,但不會釋放「鎖標誌」,使用CPU能夠調度其它線程htm

yield:只是使當前線程從新回到可執行狀態,因此執行yield()的線程有可能在進入到可執行狀態後立刻又被執行

wait:在synchronized包括的塊中使用wait,線程暫停執行,會釋放synchronized的「鎖標誌」,直到notify()或notifyAll()後纔會喚醒

join:等待調用的線程執行完後,在繼續執行當前線程

使用sleep和yield例子:

public class MyRunnable implements Runnable {

    @Override
    public void run() {
        Thread.yield();
        try {
            Thread.sleep(3000); //暫停毫秒爲單位,能夠經過interrupt拋出異常
            System.out.println(Thread.currentThread());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Thread(new MyRunnable()).start();
    }
}

wait使用:

public class MyRunnable implements Runnable {
    private Object value;

    public MyRunnable(Object value) {
        this.value = value;
    }

    @Override
    public void run() {
        synchronized (value) {
            try {
                System.out.println("執行wait");
                value.wait();
                System.out.println(Thread.currentThread());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Object lock = new Object();
        new Thread(new MyRunnable(lock)).start();
        try {
            Thread.sleep(2000);
            synchronized (lock) {
                System.out.println("執行notify");
                lock.notify();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

執行結果:

能夠發現是當線程調用wait後,是主線程調用了notify後,線程才繼續執行

join例子:

public class MyRunnable implements Runnable {

    @Override
    public void run() {
            try {
                System.out.println("執行sleep");
                Thread.sleep(5000);
                System.out.println(Thread.currentThread());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start();
        try {
            thread.join();
            System.out.println("執行join後");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

執行結果

 

interrupt操做

這個方法只會給線程設置一個爲true的中斷標誌(中斷標誌只是一個布爾類型的變量),而設置以後,則根據線程當前的狀態進行不一樣的後續操做。

1. 若是線程的當前狀態處於非阻塞狀態,那麼僅僅是線程的中斷標誌被修改成true而已;

2. 若是線程的當前狀態處於阻塞狀態,那麼在將中斷標誌設置爲true後,還會有以下三種狀況之一的操做:

(1) 若是是wait、sleep以及jion三個方法引發的阻塞,那麼會將線程的中斷標誌從新設置爲false,並拋出一個InterruptedException;
(2) 若是是java.nio.channels.InterruptibleChannel進行的io操做引發的阻塞,則會對線程拋出一個ClosedByInterruptedException;(待驗證)
(3) 若是是輪詢(java.nio.channels.Selectors)引發的線程阻塞,則當即返回,不會拋出異常。(待驗證)
若是在中斷時,線程正處於非阻塞狀態,則將中斷標誌修改成true,而在此基礎上,一旦進入阻塞狀態,則按照阻塞狀態的狀況來進行處理;例如,一個線程在運行狀態中,其中斷標誌被設置爲true,則此後,一旦線程調用了wait、jion、sleep方法中的一種,立馬拋出一個InterruptedException,且中斷標誌被清除,從新設置爲false。
經過上面的分析,咱們能夠總結,調用線程類的interrupted方法,其本質只是設置該線程的中斷標誌,將中斷標誌設置爲true,並根據線程狀態決定是否拋出異常。所以,經過interrupted方法真正實現線程的中斷原理是:開發人員根據中斷標誌的具體值,來決定如何退出線程。

參考:http://www.javashuo.com/article/p-kpmzihkf-ck.html

public class MyRunnable implements Runnable {

    @Override
    public void run() {
        try {
            System.out.println("執行sleep");
            Thread.sleep(5000); //當在暫停中調用interrupt,就拋出了異常InterruptedException
            System.out.println(Thread.currentThread());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start();
        thread.interrupt();
    }
}

執行結果:

 

setDaemon操做

線程默認false是用戶線程,經過setDaemon(true)設置線程爲守護線程

只能在start以前設置,否則會報IllegalThreadStateException異常

用戶線程和守護線程的區別:

1.主線程結束後用戶線程還會繼續運行

2.若是沒有用戶線程,都是守護線程,那麼JVM結束。

例子:

public class MyRunnable implements Runnable {

    @Override
    public void run() {
        try {
            System.out.println("執行sleep");
            Thread.sleep(5000); //當在暫停中調用interrupt,就拋出了異常InterruptedException
            System.out.println(Thread.currentThread());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.setDaemon(true);
        thread.start();
        try {
            Thread.sleep(2000);
            System.out.println("結束程序");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

結果:

能夠看到沒有等線程thread執行完,程序就結束了 

相關文章
相關標籤/搜索