java線程(二)

java線程(二)

之前提到了java線程的啓動方式,現在來介紹一下控制線程的工具

控制線程的工具

join

package cn.sc.thread;

import java.util.concurrent.TimeUnit;

public class ThreadJoinTest {
    public static void main(String[] args) throws InterruptedException {
        JoinThread joinThread = new JoinThread();

        for (int i = 0; i < 3; i++) {
            System.out.println(Thread.currentThread().getName() + i);
            if (1 == i) {
                long startTime=System.currentTimeMillis();
                joinThread.start();
                joinThread.join();
                System.out.println(System.currentTimeMillis()-startTime);
            }
        }


    }


}

class JoinThread extends Thread {

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println(currentThread().getName() + i);
            if (1 == i) {
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

運行後輸出

main0
main1
Thread-00
Thread-01
Thread-02
2006
main2

我們可以看到joinThread在調用了join方法之後,main方法被阻塞了,知道joinThread的運行體完全運行完成之後,main方法才繼續運行。
準確的說:
當A線程在運行過程中調用了B線程的join,那麼A線程會一直阻塞,直到B線程運行完畢,A線程重新進入runnable狀態
join的其他幾種形式

join():等待被join的線程執行完畢
join(long millis):等待被join的線程的時間最長爲millis毫秒。如果在millis毫秒內被join()的線程還沒有執行結束,則不再等待。
join(long millis,int nanos):等待被join的線程最長爲millis豪秒,nanos豪微秒。

Daemon

Daemon意爲守護神。Daemen是在後臺運行的,它的任務是爲其他線程提供服務,這種線程被稱爲“後臺線程(Daemon Thread)”,又稱爲“守護線程”或“精靈線程”。JVM的垃圾回收線程就是典型的後臺線程。
後臺線程的特徵:如果所有的前臺線程都死亡了,後臺線程也會自動死亡。

package cn.sc.thread;

import java.util.concurrent.TimeUnit;

public class DaemonThreadTest {

    public static void main(String[] args) {

        DaemonThread daemonThread = new DaemonThread();
        daemonThread.setDaemon(true);
        long startTime=System.currentTimeMillis();
        daemonThread.start();
        long endTime = System.currentTimeMillis();
        long period=endTime-startTime;
        System.out.println("main thread ends "+period);
    }

}

class DaemonThread extends Thread{
    @Override
    public void run() {
        System.out.println(currentThread().getName()+" daemon thread");
        System.out.println("is daemon thread :"+ isDaemon());

        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("daemon thread ends");
    }
}

運行後,輸出

main thread ends 0
Thread-0 daemon thread
is daemon thread :true

通過調用setDaemon(true)方法,我們將daemonThread設置爲了後臺線程。
main線程默認是前臺線程。
前臺線程創建中創建的子線程默認是前臺線程,後臺線程中創建的線程默認是後臺線程。
我們可以看到在main方法運行完成之後,daemonThread並沒有運行後面的代碼,而是直接死亡了。

sleep

讓當前的正在執行的線程暫停指定的時間,並進入阻塞狀態。在其睡眠的時間段內,該線程由於不是處於就緒狀態,因此不會得到執行的機會。即使此時系統中沒有任何其他可執行的線程,出於sleep()中的線程也不會執行。因此sleep()方法常用來暫停線程執行。
sleep()是一個靜態方法,可以通過Thread.sleep(long millis)直接調用

yield

yield()方法是一個和sleep()方法有點相似的方法,它也是Thread類提供的一個靜態方法。它也可以讓當前正在執行的線程暫停,但它不會阻塞該線程,只是將該線程轉入runnbale就緒狀態。yeild()只是讓當前線程暫停一下,讓系統的線程調度器重新調度一次,完全可能的情況是:當某個線程調用了yield()線程暫停之後,線程調度器又將其調度出來重新執行。
當某個線程調用了yield()方法暫停之後,只有優先級與當前線程相同,或者優先級比當前線程更高的處於就緒狀態的線程纔會獲得執行機會。

package cn.sc.thread;

public class YieldThreadTest {
    public static void main(String[] args) {
        YieldThread yieldThread1 = new YieldThread();
        YieldThread yieldThread2 = new YieldThread();
        yieldThread1.setPriority(Thread.MAX_PRIORITY);
        yieldThread2.setPriority(Thread.MIN_PRIORITY);
        yieldThread1.start();
        yieldThread2.start();
    }
}

class YieldThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(currentThread().getName()+" "+i);
            if(2==i){
                Thread.yield();
            }
        }

    }
}

運行之後可以看到“優先度最高”和“優先度最低”線程是交叉執行的,這是因爲現在的cpu大多數是多核的原因。如果用戶的計算機是單核的,就能看到線程優先級的效果。

yield()方法和sleep()的區別如下:
1. sleep()方法暫停當前線程後,會給其他線程執行機會,不會理會其他線程的優先級;但yield()只會給優先級相同,或優先級更高的線程執行機會。
2. sleep()方法會將線程轉入阻塞狀態,直到經過阻塞時間纔會轉入就緒狀態;而yield()不會講線程轉入阻塞狀態,它只是將當前線程進入就緒狀態。
3. sleep()方法的聲明拋出了InterruptedException異常,所以調用sleep()方法時要麼捕捉改異常,要麼拋出該異常。
4. sleep()方法比yield()方法具有更好的可移動性,所以建議不要使用yield()方法來控制併發線程的執行。

Prority

setPriority用於設置線程的優先級

終止線程

終止線程有以下兩種方法
1. 當此線程線程執行體執行完畢或發生了異常。
2. 使用interrupt中斷線程,可以通過isInterrupted來判斷是否被中斷。如果一個線程在sleep的過程中調用了 interrupt方法會報錯java.lang.InterruptedException: sleep interrupted。wait的時候被interrupt會報錯 java.lang.IllegalMonitorStateException
3. 使用stop強行終止線程。stop方法已經註解了@Deprecated,且使用stop方法是很危險的,就象突然關閉計算機電源,而不是按正常程序關機一樣,可能會產生不可預料的結果,不建議使用此方法。

快速結束

package cn.sc.thread;

public class StopThreadTest {
    public static void main(String[] args) {
        StopThread stopThread = new StopThread();
        stopThread.start();
        for (int i = 0; i < 100; i++) {
            if(50==i){
                stopThread.setStop(true);
            }
        }

    }
}

class StopThread extends Thread{
    private boolean stop=false;

    public void setStop(boolean stop) {
        this.stop = stop;
    }

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

拋出異常

package cn.sc.thread;

public class StopThreadTest {
    public static void main(String[] args) {
        StopThread stopThread = new StopThread();
        stopThread.start();

    }
}

class StopThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(currentThread().getName()+" "+i);
            if(5==i){
                throw new NullPointerException();
            }
        }
    }
}

interrupt

package cn.sc.thread;


public class InterruptThreadTest {

    public static void main(String[] args) throws InterruptedException {
        InterruptThread interruptThread = new InterruptThread();
        interruptThread.start();
        Thread.sleep(1);
        interruptThread.interrupt();
    }
}

class InterruptThread extends Thread{
    @Override
    public void run() {
        while (!isInterrupted()){
            System.out.println("not interrupted");
        }
    }
}

參考
http://www.cnblogs.com/lwbqqyumidi/p/3804883.html
https://www.cnblogs.com/HDK2016/p/6854683.html#a36

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