Java線程相關方法

Java線程相關方法

1. sleep

  • public static native void sleep(long millis) throws InterruptedException

當millis小于0的時候拋出IllegalArgumentException,當該線程被中斷時,拋出InterruptedException

  • public static void sleep(long millis, int nanos) throws InterruptedException

當millis小于0,或者nanos不在0 ~ 999999范圍內的時候拋出IllegalArgumentException,當該線程被中斷時,拋出InterruptedException。

該方法使當前線程暫時停止運行,但是它并不釋放對象鎖。也就是說如果有synchronized同步方法,或同步塊,其它線程仍然不能訪問加鎖的代碼。

public class Main {

    public static void main(String[] args)  {
        Thread t = new Thread(new FiveSecondSleepRunnable());
        t.start();
        //t.interrupt();
    }

    private static class FiveSecondSleepRunnable implements Runnable{
        @Override
        public void run() {
            try {
                StopWatch stopWatch = new StopWatch();
                stopWatch.start();

                Thread.sleep(5000);

                stopWatch.stop();
                System.out.println("Sleep " + stopWatch.getTime() + " millisecond");
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("I am interrupted");
            }
        }
    }
}

結果如下:
1.png

當線程t被其它線程中斷時, 即注釋的代碼t.interrupt();啟用時,會拋出異常,結果如下:

2.png

2.join

  • public final synchronized void join(long millis) throws InterruptedException
  • public final synchronized void join(long millis, int nanos) throw InterruptedException
  • public final void join() throws InterruptedException

當一個線程調用join方法,其它線程要等待該線程到時間結束,或者到該線程生命結束。

public class Example {

    public static void main(String[] args) {
        Thread t1 = new Thread(new MyRunnable(), "t1");
        Thread t2 = new Thread(new MyRunnable(), "t2");
        Thread t3 = new Thread(new MyRunnable(), "t3");

        t1.start();

        //start second thread after waiting for 2 seconds or if it's dead
        try {
            t1.join(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        t2.start();

        //start third thread only when first thread is dead
        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        t3.start();

        //let all threads finish execution before finishing main thread
        try {
            t1.join();
            t2.join();
            t3.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("All threads are dead, exiting main thread");
    }
}

class MyRunnable implements Runnable{

    @Override
    public void run() {
        System.out.println("Thread started:::"+Thread.currentThread().getName());
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Thread ended:::"+Thread.currentThread().getName());
    }
}

如上代碼,t2線程要等待t1線程執行2000毫秒后才會執行,t3線程要等到t1線程執行結束才能執行。主線程要等到t1,t2,t3線程都結束時才會打印出All threads are dead, exiting main thread。結果如下

3.png

3.yield

public static native void yield()

該方法暗示調度器,線程自己放棄當前對處理器的使用權,但是這只是一個暗示,調度器可以忽視。yield和sleep的區別在于,sleep不管線程池中是否有可運行狀態的線程,都會使線程進入TIMED_WAITING狀態并且至少會等待超時時間到達后才會再次執行。而yield則是線程放棄自己對處理器的使用權,進入RUNNABLE狀態,若此時沒有線程使用處理器,那么它又會進入RUNNING狀態。

4.interrupt

public void interrupt()

該方法并不是真正地去中斷目標線程,而是設置目標線程的中斷狀態/標志,至于如何去響應這個中斷,則是由編程人員來決定。

If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.

If this thread is blocked in an I/O operation upon an InterruptibleChannel then the channel will be closed, the thread’s interrupt status will be set, and the thread will receive a ClosedByInterruptException.

If this thread is blocked in a Selector then the thread’s interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector’s wakeup method were invoked.

If none of the previous conditions hold then this thread’s interrupt status will be set.

前三種情形其實是描述了如果線程處于等待狀態或是阻塞在某一種資源上,那么 interrupt() 方法會使得線程跳出這種狀態繼續執行下去。第四種情形則描述了如果線程正在正常執行,那么 interrupt() 的效果則是設置了線程的中斷狀態,至于怎么處理這種狀態,可以選擇忽略也可以按需處理。

某些API有中斷處理,如

  • Object.wait()/Thread.sleep()
  • 大部分java.util.concurrent包里的類
  • Java NIO,但是不是使用InterruptedException,而是使用ClosedByInterruptException

對于這些Api,我們可以在try-catch中對中斷做出處理,如

public class Main {

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new MyThread();

        thread.start();

        TimeUnit.SECONDS.sleep(5);

        thread.interrupt();
    }
}

class MyThread extends Thread {
    public void run() {
        System.out.println("Sleeppppppppppp");

        try {
            TimeUnit.SECONDS.sleep(100);
            System.out.println("Awakeeeeeeeee");
        } catch (InterruptedException e) {
            System.out.println("I am interrupted");
        }
    }
}

MyThread線程sleep 100秒,主線程在運行5秒之后中斷MyThread。在try-catch塊中,我們進入處理,輸入I am interrupted。結果如圖,首先輸出Sleeppppppppppp,但是并沒有來得及輸出Awakeeeeeeeee就中斷了。

4.png

而對于沒有中斷處理的情況,就需要我們自己判斷線程中斷狀態,作出相應處理。如下,修改MyThread類,main函數不變。我們在while循環中做業務處理,但是因為是無線循環,我們需要判斷中斷狀態,如果線程被中斷,我們就跳出循環。

class MyThread extends Thread {
    public void run() {
        while (true) {
            // Do what you what-does-java-lang-thread-interrupt-do
            // ...
            if (Thread.currentThread().isInterrupted()) {
                System.out.println("I am interrupted");
                break;
            }
        }
        System.out.println("Thread exit");
    }
}

結果如下圖,通過判斷線程中斷狀態來結束線程。

5.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容