執行緒:sleep()、wait()、yield()和join()方法
阿新 • • 發佈:2019-01-06
1.sleep()和wait()
這兩個方法都可以讓呼叫它的執行緒沉睡(sleep)/停止執行(wait)指定的時間,到了這個時間,執行緒就會自動醒來,變為可執行狀態(RUNNABLE)。public static native void sleep(long millis) throws InterruptedException;
public static void sleep(long millis, int nanos) throws InterruptedException
public final void wait() throws InterruptedException
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException
Parameters:
millis - the length of time to sleep in milliseconds.毫秒數
nanos - 0-999999 additional nanoseconds to sleep.納秒數
呼叫sleep()方法並不會讓執行緒釋放它所持有的同步鎖;而且在這期間它也不會阻礙其它執行緒的執行。
當呼叫了某個物件的wait()方法時,當前執行的執行緒就會轉入WAITING狀態,等待別的執行緒再次呼叫這個物件的notify()或者notifyAll()方法喚醒它,或者到了指定的最大等待時間,執行緒自動醒來。如果執行緒呼叫了某個物件的wait()方法,這個執行緒就會釋放這個物件所持有的同步資源(不會釋放其他物件的同步鎖)。
- package edu.hust.test;
-
publicclass ThreadSleep implements Runnable {
- /*
- * 讓執行緒睡眠的理由很多,比如(1)認為該執行緒執行得太快,需要減緩一下,以便和其他執行緒協調;(2)查詢當時的股票價格,每睡5分鐘查詢一次,可以節省頻寬,而且即時性要求也不那麼高。
- * 注意:時間的精確性。執行緒醒來之後不會馬上執行,而要等待cpu給其分配時間片。因此sleep()中指定的時間並不是執行緒不執行的精確時間!所以不能依賴sleep()方法提供十分精確的定時。
- * 我們可以看到很多應用程式用sleep()作為定時器,實際是不精確的。
- *
- *
- * Thread.sleep(5 * 1000)和Thread.currentThread().sleep(5 * 1000)沒區別:都表示讓當前執行緒sleep 5秒.
- * 一個是通過類獲取靜態方法,一個是通過例項物件獲得靜態方法(sleep()為靜態方法).
- *
- * 注意:sleep並不是Thread的一個STATE
- */
- publicvoid execute() {
- synchronized(this) {
- try {
- System.out.println(Thread.currentThread().getName() + ", sleep()前");
- Thread.sleep(1000);
- System.out.println(Thread.currentThread().getName() + ", sleep()後");
- } catch (InterruptedException e) {
- System.out.println(Thread.currentThread().getName() + ", 誰把我吵醒了.....");
- }
- //此處如果使用System.err, 會有很意外的結果。System.out和System.err的區別請見blog
- System.out.println(Thread.currentThread().getName() + ", run()結束..進入TERMINATED狀態");
- }
- }
- publicvoid run() {
- execute();
- }
- publicstaticvoid main(String[] args) throws InterruptedException {
- ThreadSleep threadSleep = new ThreadSleep();
- Thread[] threads = new Thread[5];
- System.out.println(Thread.currentThread().getName() + "執行緒的狀態為:" + Thread.currentThread().getState());
- for (Thread thread : threads) {
- thread = new Thread(threadSleep);
- thread.start();
- if ("Thread-1".equals(thread.getName()) || "Thread-3".equals(thread.getName()))
- thread.interrupt();
- }
- }
- /*
- * 某次執行結果:
- * main執行緒的狀態為:RUNNABLE
- * Thread-1, sleep()前
- * Thread-1, 誰把我吵醒了.....
- * Thread-1, run()結束..進入TERMINATED狀態
- *
- * Thread-3, sleep()前
- * Thread-3, 誰把我吵醒了.....
- * Thread-3, run()結束..進入TERMINATED狀態
- *
- * Thread-0, sleep()前
- * Thread-0, sleep()後
- * Thread-0, run()結束..進入TERMINATED狀態
- *
- * Thread-2, sleep()前
- * Thread-2, sleep()後
- * Thread-2, run()結束..進入TERMINATED狀態
- *
- * Thread-4, sleep()前
- * Thread-4, sleep()後
- * Thread-4, run()結束..進入TERMINATED狀態
- *
- * 從執行結果可以得出很多結論, 其中之一是:呼叫sleep()方法並不會讓執行緒釋放它所持有的同步鎖;而且在這期間它也不會阻礙其它執行緒的執行。
- *
- * */
- }
- package edu.hust.test;
- class MyThread1 implements Runnable {
- private Object obj;
- public MyThread1(Object o) {
- obj = o;
- }
- publicvoid run() {
- synchronized (obj) { //這裡是給obj物件(也就是str="愛吃土豆")加鎖, 如寫成synchronized (this), 則表示是給myThread1加鎖.
- try {
- System.out.println("MyThread1進入wait狀態");
- obj.wait();
- System.out.println("MyThread1被notify");
- } catch (InterruptedException e) {
- System.err.println("誰把我吵醒了.....");
- }
- }
- }
- }
- class MyThread2 implements Runnable {
- private Object obj;
- public MyThread2(Object o) {
- obj = o;
- }
- publicvoid run() {
- synchronized (obj) { //這裡是給obj物件(也就是str="愛吃土豆")加鎖, 如寫成synchronized (this), 則表示是給myThread2加鎖.
- System.out.println("MyThread2呼叫notify()方法");
- obj.notify();
- }
- }
- }
- publicclass ThreadWait {
- publicstaticvoid main(String[] args) {
- //錯誤的寫法, 這裡myThread1和myThread2操作的是兩個不同的物件.
- //Thread myThread1 = new Thread(new MyThread1(new String("愛吃土豆")));
- //Thread myThread2 = new Thread(new MyThread2(new String("愛吃土豆")));
- //正確的寫法, 這裡myThread1和myThread2操作的是同一個物件.
- String str = "愛吃土豆";
- Thread myThread1 = new Thread(new MyThread1(str));
- Thread myThread2 = new Thread(new MyThread2(str));
- myThread1.start();
- myThread2.start();
- }
- /*
- * 執行結果:
- * MyThread1進入wait狀態
- * MyThread2呼叫notify()方法
- * MyThread1被notify
- *
- * 這裡使用了synchronized塊來包裝某個例項物件(String str = "愛吃土豆")的wait()和notify()方法, 這是由於呼叫這兩個方法的時候執行緒必須獲得同步鎖.
- * 如果synchronized包裝的不是同一個例項物件的wait()和notify()方法, 則表示給wait()和notify()加的鎖不是同一把鎖,eg:將synchronized(lock)改為synchronized(this).
- * 將會丟擲java.lang.IllegalMonitorStateException, 告訴你current thread not owner.
- *
- * */
- /*
- * 摘錄:
- * 多執行緒常用的一些方法: wait(),wait(long),notify(),notifyAll()
- * wait() 是使持有物件鎖的執行緒釋放鎖;
- * wait(long) 是使持有物件鎖的執行緒釋放鎖時間為long(毫秒)後,再次獲得鎖,wait()和wait(0)等價;
- * notify() 是喚醒一個正在等待該物件鎖的執行緒,如果等待的執行緒不止一個,那麼被喚醒的執行緒由jvm確定;
- * notifyAll 是喚醒所有正在等待該物件鎖的執行緒.
- *
- * 應該優先使用notifyAll()方法, 因為喚醒所有執行緒比喚醒一個執行緒更容易讓jvm找到最適合被喚醒的執行緒.
- * 對於上述方法,只有在當前執行緒中才能使用,否則報執行時錯誤java.lang.IllegalMonitorStateException: current thread not owner.
- * 從實現角度來分析:
- * 線上程呼叫wait()方法時,需要把它放到一個同步段裡,否則將會出現"java.lang.IllegalMonitorStateException: current thread not owner"的異常。
- *
- * */
- }
- package edu.hust.test;
- publicclass ThreadWait2 implements Runnable {
- private Object monitor1 = new Object();
- private Object monitor2 = new Object();
- publicvoid run() {
- synchronized (monitor1) {
- System.out.println("monitor1被鎖住了");
- synchronized (monitor2) {
- System.out.println("monitor2被鎖住了");
- try {
- System.out.println("monitor2進入wait()狀態");
- monitor2.wait();
- } catch (InterruptedException e) {
- System.out.println("誰把我吵醒了.....");
- }
- }
- }
- }
- publicvoid getMonitor() throws InterruptedException {
- Thread.sleep(3 * 1000); //讓main Thread延遲3秒執行, 使myThread獲得足夠時間進行執行緒初始化
-