Object#wait()與Object#wait(long)的區別,Object的wait方法與線程sleep方法的區別


例子

例1 最基礎的等待-通知

下面一個例子,一個線程"waiting"在同步代碼塊調用了Object#wait()方法,另一個線程"timedWaiting"調用了Object#wait(3000)等待3000ms,主線程sleep 5000ms后喚醒所有線程。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;

/**
 * @see Object#wait(long) 等待對應的毫秒數(不為0)或者被喚醒,執行后續代碼
 * @see Object#wait() 只有被喚醒(底層源碼調用wait 0 ms)才能執行后續代碼
 * @author rhyme
 * @date 2020/5/30 11:38
 */
@Slf4j
public class ObjectWaitMain {
  private static final Object lock = new Object();

  private static final Runnable waiting =
      () -> {
        synchronized (lock) {
          try {
            log.info("Thread: {}, will Object#wait()", Thread.currentThread().getName());
            lock.wait();
            log.info("Thread: {} is notified.", Thread.currentThread().getName());
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      };

  private static final Runnable timedWaiting =
      () -> {
        synchronized (lock) {
          try {
            log.info(
                "Thread: {}, will be notified or wait 3000 milliseconds.",
                Thread.currentThread().getName());
            lock.wait(3000);
            log.info(
                "Thread: {}, after being notified or wait 3000 milliseconds.",
                Thread.currentThread().getName());

          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      };

  public static void main(String[] args) throws InterruptedException {

    CompletableFuture.allOf(
        CompletableFuture.runAsync(waiting), CompletableFuture.runAsync(timedWaiting));

    // 主線程sleep5000ms,當3000ms后"timedWaiting"線程執行"wait(3000)"后的代碼塊
    // 如果"timedWaiting"線程在3000ms被notify,那么會立即執行后續代碼,不會wait 3000ms
    TimeUnit.MILLISECONDS.sleep(5000);

    synchronized (lock) {
      log.info("main will notifyAll waiting thread.");
      lock.notifyAll();
    }
    log.info("main end.");
  }
}

執行結果:

 

 

例2 Object#wait(long)的參數大於0與等於0

測試類代碼

/**
 * @author rhyme
 * @date 2020/5/31 0:43
 */
@Slf4j
public class ThreadPoolExecutorTest {
  private ThreadPoolExecutor threadPoolExecutor;

  @Before
  public void initializeThreadPoolExecutor() {
    threadPoolExecutor =
        new ThreadPoolExecutor(4, 8, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(4));
  }

  @After
  public void teardown() throws InterruptedException {
    threadPoolExecutor.shutdown();

    TimeUnit.SECONDS.sleep(2);
    threadPoolExecutor = null;
  }

 

大於0

/**
   * 當 {@link Object#wait(long)}的參數是大於0, 線程wait對象的毫秒數后, 不需被喚醒, 就可再次獲取鎖執行wait后續代碼
   * @see Object#wait(long)
   */
  @Test
  public void synchronizedTimedWaitingTest() {
    Runnable timedWaiting =
        () -> {
          synchronized (this) {
            while (true) {
              try {
                log.info("before Object#wait(1);");
                this.wait(1);
                log.info("after Object#wait(1);");
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
            }
          }
        };

    threadPoolExecutor.execute(timedWaiting);
  }

執行結果:

 

等於0或Object#wait()

/**
   * 當 {@link Object#wait(long)}的參數是0, 線程只能是被喚醒后, 才能再次獲取鎖執行wait后續代碼
   * @see Object#wait()
   */
  @Test
  public void synchronizedWaitingTest() {
    Runnable timedWaiting =
        () -> {
          synchronized (this) {
            while (true) {
              try {
                log.info("before Object#wait(0);");
                // 與"this.wait()"等價
                this.wait(0);
                log.info("after Object#wait(0);");
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
            }
          }
        };

    threadPoolExecutor.execute(timedWaiting);
  }

執行結果, 該線程一直wait, 線程池關閉結束, UT結束:

 

總結

Object#wait(long) 等待對應的毫秒數后(不為0)或者在等待過程中被喚醒后,就能再次獲取鎖並且獲得時間片后執行wait后面代碼;
Object#wait() 只有被喚醒后(底層源碼調用wait 0 ms)才能再次獲取鎖執行wait后面代碼;

Thread#sleep或TimeUnit#sleep, 除非當前sleep的線程被interrupt否則必須sleep對應的時間才能執行后續代碼, 並且如果之前獲取到鎖, 不會釋放鎖.

Object#wait()方法源碼如下:

public final void wait() throws InterruptedException {
        wait(0);
}
 public final native void wait(long timeout) throws InterruptedException;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM