isAlive() 函数


isAlive() 函数可判断当前线程是否处于活跃状态。

创建代码 test9.java

创建 test9.java 文件,代码如下所示:

  1. class MyThread extends Thread{
  2. @Override
  3. public void run(){
  4. System.out.println("运行中:" + this.isAlive());
  5. }
  6. }
  7. public class test9{
  8. public static void main(String[] args){
  9. MyThread myThread = new MyThread();
  10. System.out.println("开始:" + myThread.isAlive());
  11. myThread.start();
  12. System.out.println("结束:" + myThread.isAlive());
  13. }
  14. }

class MyThread extends Thread{ @Override public void run(){ System.out.println(“运行中:” + this.isAlive()); } } public class test9{ public static void main(String[] args){ MyThread myThread = new MyThread(); System.out.println(“开始:” + myThread.isAlive()); myThread.start(); System.out.println(“结束:” + myThread.isAlive()); } }

test9 运行结果

线程的休眠与活跃 - 图1
可以从上述代码可以看出,一个线程在 new 出来之后,处于非活跃状态,而在运行中与结束后,都属于活跃状态。

test9 对于结束依旧是 true 的解析

结束 true 这个值是不确定的,因为 mythread 目前可能还没有结束,所以此时依旧算作活跃状态。

sleep() 函数


sleep() 函数的作用是指定的毫秒内让 当前执行的线程 休眠(停止运行)。通常在一个正在结束的线程后面使用 sleep() 的话,可以更正确的展示出 isAlived() 函数的作用。并且可以相对释放性能资源。

创建代码 test10.java

创建 test10.java 文件,代码如下所示:

  1. class MyThread extends Thread{
  2. @Override
  3. public void run(){
  4. System.out.println("运行中:" + this.isAlive());
  5. }
  6. }
  7. public class test10{
  8. public static void main(String[] args){
  9. MyThread myThread = new MyThread();
  10. System.out.println("开始:" + myThread.isAlive());
  11. myThread.start();
  12. System.out.println("结束:" + myThread.isAlive());
  13. try{
  14. myThread.sleep(1000);
  15. } catch(Exception exception){
  16. exception.printStackTrace();
  17. }
  18. System.out.println("睡眠后:" + myThread.isAlive());
  19. }
  20. }

class MyThread extends Thread{ @Override public void run(){ System.out.println(“运行中:” + this.isAlive()); } } public class test10{ public static void main(String[] args){ MyThread myThread = new MyThread(); System.out.println(“开始:” + myThread.isAlive()); myThread.start(); System.out.println(“结束:” + myThread.isAlive()); try{ myThread.sleep(1000); } catch(Exception exception){ exception.printStackTrace(); } System.out.println(“睡眠后:” + myThread.isAlive()); } }

test10 运行结果

线程的休眠与活跃 - 图2

线程的生命周期


java 中的线程的生命周期常见的 6 种状态如下所示,状态的枚举类位置在:

  1. Thread.State.NEW
  2. Thread.State.RUNNABLE
  3. Thread.State.BLOCKED
  4. Thread.State.WAITING
  5. Thread.State.TIMED_WAITING
  6. Thread.State.TERMINATED

Thread.State.NEW Thread.State.RUNNABLE Thread.State.BLOCKED Thread.State.WAITING Thread.State.TIMED_WAITING Thread.State.TERMINATED
线程的休眠与活跃 - 图3
有的文章或博客会说 Java 的线程是只有 5 种,那是因为他们 JDK 依旧停留在 1.5 的版本所导致的。

新建:Thread.State.NEW

Thread.State.NEW 指尚未启动的线程的线程状态。

  1. /**
  2. * Thread state for a thread which has not yet started.
  3. */
  4. NEW,

/* Thread state for a thread which has not yet started. */ NEW,
new Thread() 之后还没 start () 的时候即是 Thread.State.NEW 状态。

可运行:Thread.State.RUNNABLE

Thread.State.RUNNABLE 指:可运行线程的线程状态。处于可运行状态的线程正在 Java 虚拟机中执行,但它可能正在等待来自操作系统(如处理器)的其他资源。

  1. /**
  2. * Thread state for a runnable thread. A thread in the runnable
  3. * state is executing in the Java virtual machine but it may
  4. * be waiting for other resources from the operating system
  5. * such as processor.
  6. */
  7. RUNNABLE,

/* Thread state for a runnable thread. A thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor. / RUNNABLE,
几乎所有运行、运行中都在使用这个状态。

阻塞:Thread.State.BLOCKED

Thread.State.BLOCKED 指阻塞状态,等待监视器锁定时被阻止的线程的线程状态。处于阻塞状态的线程正在等待监视器锁进入同步块 / 方法或在调用后重新输入同步块 / 方法

  1. /**
  2. * Thread state for a thread blocked waiting for a monitor lock.
  3. * A thread in the blocked state is waiting for a monitor lock
  4. * to enter a synchronized block/method or
  5. * reenter a synchronized block/method after calling
  6. * {@link Object#wait() Object.wait}.
  7. */
  8. BLOCKED,

/* Thread state for a thread blocked waiting for a monitor lock. A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling {@link Object#wait() Object.wait}. */ BLOCKED,
前文里面提到的用 synchronized 同步锁,锁住该线程之后,其它线程等待这个线程时的等待状态。阻塞状态属于多线程开发中最重要的状态。
例如 Socket 的 serverSocket.accept() , netty 中的 IO 多路复用技术,都是采取阻塞 Thread.State.BLOCKED 机制进行设计的。

等待:Thread.State.WAITING

Thread.State.WAITING 指等待线程的线程状态。由于调用以下方法之一,线程处于等待状态:

  • Object.wait()
  • Thread.join()
  • LockSupport#park()

处于等待状态的线程正在等待另一个线程执行特定操作。例如,对某个对象调用了 Object.wait() 的线程正在等待另一个线程对该对象调用 Object.notify() 或 Object.notifyAll() 。调用了 thread.join() 的线程正在等待指定线程终止。

  1. /**
  2. * Thread state for a waiting thread.
  3. * A thread is in the waiting state due to calling one of the
  4. * following methods:
  5. * <ul>
  6. * <li>{@link Object#wait() Object.wait} with no timeout</li>
  7. * <li>{@link #join() Thread.join} with no timeout</li>
  8. * <li>{@link LockSupport#park() LockSupport.park}</li>
  9. * </ul>
  10. *
  11. * <p>A thread in the waiting state is waiting for another thread to
  12. * perform a particular action.
  13. *
  14. * For example, a thread that has called <tt>Object.wait()</tt>
  15. * on an object is waiting for another thread to call
  16. * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
  17. * that object. A thread that has called <tt>Thread.join()</tt>
  18. * is waiting for a specified thread to terminate.
  19. */
  20. WAITING,

/* Thread state for a waiting thread. A thread is in the waiting state due to calling one of the following methods:

  • {@link Object#wait() Object.wait} with no timeout
  • {@link #join() Thread.join} with no timeout
  • {@link LockSupport#park() LockSupport.park}

A thread in the waiting state is waiting for another thread to perform a particular action. For example, a thread that has called Object.wait() on an object is waiting for another thread to call Object.notify() or Object.notifyAll() on that object. A thread that has called Thread.join() is waiting for a specified thread to terminate. */ WAITING,
暂时可以理解线程用了那几个函数之一,就会进入这个状态

计时等待:Thread.State.TIMED_WAITING

Thread.State.TIMED_WAITING 具有指定等待时间的等待线程的线程状态。由于使用指定的正等待时间调用以下方法之一,线程处于定时等待状态:

  • Thread.sleep()
  • Object#wait(long)
  • Thread#join(long)
  • LockSupport#parkNanos
  • LockSupport#parkUntil ```shell /**
  • Thread state for a waiting thread with a specified waiting time.
  • A thread is in the timed waiting state due to calling one of
  • the following methods with a specified positive waiting time:
    • {@link #sleep Thread.sleep}
    • {@link Object#wait(long) Object.wait} with timeout
    • {@link #join(long) Thread.join} with timeout
    • {@link LockSupport#parkNanos LockSupport.parkNanos}
    • {@link LockSupport#parkUntil LockSupport.parkUntil}
    / TIMED_WAITING, ``` /** Thread state for a waiting thread with a specified waiting time. A thread is in the timed waiting state due to calling one of the following methods with a specified positive waiting time:
    • {@link #sleep Thread.sleep}
    • {@link Object#wait(long) Object.wait} with timeout
    • {@link #join(long) Thread.join} with timeout
    • {@link LockSupport#parkNanos LockSupport.parkNanos}
    • {@link LockSupport#parkUntil LockSupport.parkUntil}
    / TIMED_WAITING,
    暂时可以理解线程用了那几个函数之一,就会进入这个状态,时间到了就自动退出这个状态了。

    终止:Thread.State.TERMINATED

    Thread.State.TERMINATED 指终止线程的线程状态。线程已完成执行。
    /* Thread state for a terminated thread. The thread has completed execution. / TERMINATED;
    说白了执行完了就是这个状态

    线程运行图

    线程的休眠与活跃 - 图4
    该线程运行图是笔者根据自身理解画的,笔者看过许多有关 java 线程、计算机线程之类的书籍和博客,有关于深入 java 线程的内容乱的很。
    例如上图中给你当 Running,这个状态并非 JDK 的 Thread.state 枚举中所占有的,但是也有不少人说,运行中也属于一种状态。不能把 Ready 和 Running 都归属于 Runnable 之中,毕竟启动 new 线程之后,可运行线程与正在运行线程应当属于两种状态,但事实上 JDK 的定义中确实是将 Ready 与 Running 都归属于 Runnable 之中,有没有 Running 这算是两种不同的说法。其实哪一种说法都无所谓,这一部分更重要的是概念性的知识,只要知道 Java 线程大致涵盖以上六种,大概的运行方式即可,本小节中后续内容将会模拟线程所在的各个状态,例如 NEW、Runnable、Terminated 等等等,可以让读者更直观的看到各个线程状态所处于的情况。
    后续章节笔者将会给出有关于各个状态可以调用 / 被调用的函数关系。
    在线程运行的流程上,只需理解即可,建议自己动笔画一下上面的流程图,能够更清晰的捋顺线程执行的过程,但是不要死记硬背,等做完类似于本文中各个测试与模拟之后,肯定都会理解有关线程的内容。
    另外 Java 线程是与计算机的操作系统线程互相映射的,一般操作系统会有 N 种线程,一般来说 Java 线程会与这 N 种线程进行对应的,例如有可能 Java 中的等待线程和计时等待线程在操作系统里都叫等待线程一样,不过这里也只是一个概念性知识,实际工作中没什么意义。:


    模拟 NEW、RUNNABLE、和 TERMINATED 状态


    下面利用代码的方式验证线程部分的状态值,了解线程的状态有助于程序员在监控线程时对对象所做的处理,例如哪些线程从未启动,哪些线程正在执行,哪些线程正在阻塞,哪些线程正在等待,哪些线程已经销毁了等等。这些都是与线程的生命周期息息相关的信息。
    首先验证的是 new、runnable、terminated 三种状态。
    如上文所示,new 状态是线程实例化后,还未执行 start() 函数时的状态。
    runnable 是线程进入运行时期的状态。
    terminated 是线程被销毁(运行结束)的状态。

    创建 learn1.java 文件

    其代码如下所示: ```shell public class learn1{ public static void main(String[] args){
    1. try{
    2. Thread myThread = new MyThread();
    3. System.out.println("MyThread state 1:" + myThread.getState());
    4. myThread.sleep(1000);
    5. myThread.start();
    6. myThread.sleep(1000);
    7. System.out.println("MyThread state 2:" + myThread.getState());
    8. }catch(InterruptedException e){
    9. e.printStackTrace();
    10. }
    } }

class MyThread extends Thread{ @Override public void run(){ System.out.println(“MyThread run()” + Thread.currentThread().getName()

  1. + "。该线程的状态:" + Thread.currentThread().getState());
  2. }
  3. public MyThread(){
  4. System.out.println("MyThread 无参构造的线程名" + Thread.currentThread().getName()
  5. + "。该线程的状态:" + Thread.currentThread().getState());
  6. }

}

  1. public class learn1{ public static void main(String[] args){ try{ Thread myThread = new MyThread(); System.out.println("MyThread state 1:" + myThread.getState()); myThread.sleep(1000); myThread.start(); myThread.sleep(1000); System.out.println("MyThread state 2:" + myThread.getState()); }catch(InterruptedException e){ e.printStackTrace(); } } } class MyThread extends Thread{ @Override public void run(){ System.out.println("MyThread run()" + Thread.currentThread().getName() + "。该线程的状态:" + Thread.currentThread().getState()); } public MyThread(){ System.out.println("MyThread 无参构造的线程名" + Thread.currentThread().getName() + "。该线程的状态:" + Thread.currentThread().getState()); } }
  2. <a name="l3Y2f"></a>
  3. #### learn1 执行结果
  4. ![](https://cdn.nlark.com/yuque/0/2021/png/333017/1624982887644-f4aeb372-c09b-48a8-895e-7f25b8a167be.png#clientId=u4365fbb2-de97-4&from=paste&id=u2a4819a3&margin=%5Bobject%20Object%5D&originHeight=72&originWidth=508&originalType=url&ratio=1&status=done&style=none&taskId=u21b9123a-e17e-4857-911d-36e30fe5b42)<br />由运行结果可得出 learn1 测试的运行示意图如下所示:<br />![](https://cdn.nlark.com/yuque/0/2021/png/333017/1624982887667-77661a78-3ebd-4166-8f69-235c278be85f.png#clientId=u4365fbb2-de97-4&from=paste&id=uc927f151&margin=%5Bobject%20Object%5D&originHeight=244&originWidth=373&originalType=url&ratio=1&status=done&style=none&taskId=u9cfa3110-b35f-48fe-a20f-ebfe94f5273)<br />这里有个小缺陷即:无参构造的 RUNNABLE 状态,实为 main() 函数的主线程的状态为 RUNNABLE,而非这个多线程 MyThread 的状态。
  5. <a name="XrWMf"></a>
  6. ## 模拟 TIMED_WAITING 状态
  7. 线程状态 TIME_WAITING 代表线程执行了 Thread.sleep() 方法,呈现出等待状态,等待时间到达,继续向下运行。
  8. <a name="gwK3U"></a>
  9. #### 创建 learn2.java 文件
  10. 其代码如下所示:
  11. ```shell
  12. public class learn2{
  13. public static void main(String[] args){
  14. try{
  15. Thread myThread = new MyThread();
  16. myThread.start();
  17. myThread.sleep(1000);
  18. System.out.println("MyThread state 2:" + myThread.getState());
  19. }catch(InterruptedException e){
  20. e.printStackTrace();
  21. }
  22. }
  23. }
  24. class MyThread extends Thread{
  25. @Override
  26. public void run(){
  27. try{
  28. System.out.println("sleep 开始");
  29. Thread.sleep(10000);
  30. System.out.println("sleep 结束");
  31. }catch(InterruptedException e){
  32. e.printStackTrace();
  33. }
  34. }
  35. public MyThread(){
  36. System.out.println("MyThread 无参构造的线程名" + Thread.currentThread().getName()
  37. + "。该线程的状态:" + Thread.currentThread().getState());
  38. }
  39. }

public class learn2{ public static void main(String[] args){ try{ Thread myThread = new MyThread(); myThread.start(); myThread.sleep(1000); System.out.println(“MyThread state 2:” + myThread.getState()); }catch(InterruptedException e){ e.printStackTrace(); } } } class MyThread extends Thread{ @Override public void run(){ try{ System.out.println(“sleep 开始”); Thread.sleep(10000); System.out.println(“sleep 结束”); }catch(InterruptedException e){ e.printStackTrace(); } } public MyThread(){ System.out.println(“MyThread 无参构造的线程名” + Thread.currentThread().getName() + “。该线程的状态:” + Thread.currentThread().getState()); } }

learn2.java 执行结果

由下述执行结果我们可以看出,当多线程执行 Thread.sleep() 时,该线程的状态即为 TIMED_WAITING。
线程的休眠与活跃 - 图5
线程的休眠与活跃 - 图6

模拟 BLOCKED 状态

Thread.State.BLOCKED 指阻塞状态,等待监视器锁定时被阻止的线程的线程状态。处于阻塞状态的线程正在等待监视器锁进入同步块 / 方法或在调用后重新输入同步块 / 方法

创建 learn3.java 文件

learn3.java 代码如下所示,在 learn3.java 代码中,我们使用了 synchroized 关键字
public class learn3 { public static void main(String[] args) { Thread threadA = new Thread(new Runnable() { public void run() { MyService.myMethod(); } }, “ThradA”); threadA.start(); Thread threadB = new Thread(new Runnable() { public void run() { MyService.myMethod(); } }, “ThradB”); threadB.start(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } boolean isBlocked = threadB.getState().equals(Thread.State.BLOCKED); System.out.print(“threadB.getState().equals(Thread.State.BLOCKED)” + isBlocked); } } class MyService{ public static synchronized void myMethod() { try { Thread.sleep(30000); } catch (InterruptedException e) { e.printStackTrace(); } } }

learn3 运行结果

线程的休眠与活跃 - 图7
可以看出,由于我们使用了 synchronized 与 static 两个关键字,才让线程处于阻塞状态,若只有 synchroized 不写 static 的情况下, threadB 线程不会进入阻塞状态,更改代码如下所示:
public class learn3 { public static void main(String[] args) { Thread threadA = new Thread(new Runnable() { public void run() { new MyService().myMethod(); } }, “ThradA”); threadA.start(); Thread threadB = new Thread(new Runnable() { public void run() { new MyService().myMethod(); } }, “ThradB”); threadB.start(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } boolean isBlocked = threadB.getState().equals(Thread.State.BLOCKED); System.out.print(“threadB.getState().equals(Thread.State.BLOCKED)” + isBlocked); } } class MyService{ public /static/ synchronized void myMethod() { try { Thread.sleep(30000); } catch (InterruptedException e) { e.printStackTrace(); } } }
运行结果如下所示:
线程的休眠与活跃 - 图8

synchronized 与 static synchronized 之间的区别

synchronized 是实例锁(锁在某一个实例对象上,如果该类是单例,那么该锁也具有全局锁的概念)
static synchronized 是全局锁(该锁针对的是类,无论实例多少个对象,那么线程都共享该锁)。
synchronized 是对类的当前实例(当前对象)进行加锁,防止其他线程同时访问该类的该实例的所有 synchronized 块,注意这里是“类的当前实例”, 类的两个不同实例就没有这种约束了。
那么 static synchronized 恰好就是要控制类的所有实例的并发访问,static synchronized 是限制多线程中该类的所有实例同时访问 jvm 中该类所对应的代码块。
实际上,在类中如果某方法或某代码块中有 synchronized,那么在生成一个该类实例后,该实例也就有一个监视块,防止线程并发访问该实例的 synchronized 保护块,而 static synchronized 则是所有该类的所有实例公用得一个监视块。
不过也值得注意的是,static synchronized 的效率很低,全局情况下每个线程都需要进行等待,可想而知如果 5000 个用户,同时等待某款热门抢购产品,若那个产品的剩余数量被 static synchronized 修饰了,那么每个人每次刷新页面就需要等待几千个线程读取该产品的剩余数量,若访问量过大的话导致服务器崩溃都有可能。
多线程的学习,也是不断深入了解 synchronized 的各种用法、线程在各种状态时调用的各种函数、最终达到用高并发的方式进行性能优化式的编程、编写相关框架、编写简易版的 tomcat 服务器即可,循序渐进切勿急躁,本小节优先熟悉一下线程的各种状态,第八章《脏读与对象监视器》还会对这个知识点进行讲解。

模拟 WAITING 状态
hread.State.TIMED_WAITING 具有指定等待时间的等待线程的线程状态。由于使用指定的正等待时间调用以下方法之一,线程处于定时等待状态:

  • Thread.sleep()
  • Object#wait(long)
  • Thread#join(long)
  • LockSupport#parkNanos
  • LockSupport#parkUntil

    创建 learn4.java 文件

    创建 learn4.java 文件模拟 WAITING 状态。
    public class learn4 { public static void main(String[] args) { Thread myThread = new MyThread(); myThread.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(“main 方法中 myThread 的状态:” + myThread.getState()); } } class myLock{ public static final String lock = new String(“0”); } class MyThread extends Thread{ @Override public void run() { synchronized (myLock.lock) { try { myLock.lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } }

    learn4 运行结果

    线程的休眠与活跃 - 图9

    synchronized 块详解

    synchronized 的三种用法
  • 修饰实例方法

  • 修饰静态方法
  • 修饰代码块

在前文中,我们一直使用 synchronize 修饰实例的方式,所谓的实例对象锁就是用 synchronized 修饰实例对象中的实例方法,注意是实例方法不包括静态方法,代码如下所示:
public synchronized void myMethod(){ }
在 learn3 测试中我们使用了 synchronized 修饰静态方法,当 synchronized 作用于静态方法时,其锁就是当前类的 class 对象锁。由于静态成员不专属于任何一个实例对象,是类成员,因此通过 class 对象锁可以控制静态成员的并发操作。需要注意的是如果一个线程 A 调用一个实例对象的非 static synchronized 方法,而线程 B 需要调用这个实例对象所属类的静态 synchronized 方法,是允许的,不会发生互斥现象,因为访问静态 synchronized 方法占用的锁是当前类的 class 对象,而访问非静态 synchronized 方法占用的锁是当前实例对象锁,二者的锁并不一样,所以不冲突,代码如下所示:
public static synchronized void myMethod(){ }
而在 learn4 测试中我们使用了 synchronized 修饰代码块的方式,在某些情况下,我们编写的方法体可能比较大,同时存在一些比较耗时的操作,而需要同步的代码又只有一小部分,如果直接对整个方法进行同步操作,可能会得不偿失,此时我们可以使用同步代码块的方法对需要同步的代码进行包裹,这样就无需对整个方法进行同步操作了,锁的对象是变量代码。
修饰代码块下——成员锁,锁住的对象是变量,代码如下所示:
synchronized (myLock.lock) { try { myLock.lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } }
修饰代码块下——实例对象锁,this 代表当前实例,代码如下所示:
synchronized(this) { for (int j = 0; j < 100; j++) { i++; } }
修饰代码块下——当前类的 class 对象锁,this 代表当前实例,代码如下所示:
synchronized(AccountingSync.class) { for (int j = 0; j < 100; j++) { i++; } }
大体之下, synchronized 有上述三种用法,及一共五种可能出现的样子即可,暂时只要大概了解即可,在第八章《脏读与对象监视器》中会深度对其进行讲解。
eclipse 中 synchronized 代码块提示如下所示:
线程的休眠与活跃 - 图10

wait() 函数概念

wait 属于 Object 的成员方法,一旦一个对象调用了 wait 方法,必须要采用 notify() 和 notifyAll() 方法唤醒该进程;如果线程拥有某个或某些对象的同步锁,那么在调用了 wait() 后,这个线程就会释放它持有的所有同步资源,而不限于这个被调用了 wait() 方法的对象。wait() 方法也同样会在 wait 的过程中有可能被其他对象调用 interrupt() 方法而产生。
具有指定等待时间的等待线程的线程状态。由于使用指定的正等待时间调用以下方法之一,线程处于定时等待状态。
当前线程必须拥有此对象的监视器。线程释放此监视器的所有权并等待,直到另一个线程通过调用 notify() 方法或 notifyAll() 方法通知等待此对象监视器唤醒的线程。然后,线程等待,直到它可以重新获得监视器的所有权并恢复执行。在单参数版本中,中断和虚假唤醒是可能的,并且此方法应始终在循环中使用:
synchronized (obj) { while (condition) obj.wait(); // Perform action appropriate to condition }
此方法只能由作为此对象监视器所有者的线程调用。请参阅{@code notify}方法,以了解线程成为监视器所有者的方式。


原文如下所示:
/* Causes the current thread to wait until another thread invokes the {@link java.lang.Object#notify()} method or the {@link java.lang.Object#notifyAll()} method for this object. In other words, this method behaves exactly as if it simply performs the call {@code wait(0)}.

The current thread must own this object’s monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object’s monitor to wake up either through a call to the {@code notify} method or the {@code notifyAll} method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:

  1. synchronized (obj) { while (<condition does not hold>) obj.wait(); // Perform action appropriate to condition }
This method should only be called by a thread that is the owner of this object’s monitor. See the {@code notify} method for a description of the ways in which a thread can become the owner of a monitor. @throws IllegalMonitorStateException if the current thread is not the owner of the object’s monitor. @throws InterruptedException if any thread interrupted the current thread before or while the current thread was waiting for a notification. The interrupted status of the current thread is cleared when this exception is thrown. @see java.lang.Object#notify() @see java.lang.Object#notifyAll() / public final void wait() throws InterruptedException { wait(0); }

wait() 函数与 sleep() 函数的区别

关于异常

wait() 函数不需要捕获异常
sleep() 函数必须捕获异常


关于入参

wait() 函数可以传入参数,也可以不传入参数,传入参数就是在参数结束的时间后开始等待,不传入参数就是直接等待。
sleep() 函数必须传入参数,参数就是休眠时间,时间到了就会自动醒来。


关于 API

sleep() 是 Thread 类的函数,导致此线程暂停执行指定时间,给其他线程执行机会,但是依然保持着监控状态,过了指定时间会自动恢复,调用 sleep() 方法不会释放锁对象。当调用 sleep 方法后,当前线程进入阻塞状态。目的是让出 CPU 给其他线程运行的机会。但是由于 sleep() 方法不会释放锁对象,所以在一个同步代码块中调用这个方法后,线程虽然休眠了,但其他线程无法访问它的锁对象。这是因为 sleep() 方法拥有 CPU 的执行权,它可以自动醒来无需唤醒。而当 sleep() 结束指定休眠时间后,这个线程不一定立即执行,因为此时其他线程可能正在运行。
wait() 方法是 Object 类里的方法,当一个线程执行到 wait() 方法时,它就进入到一个和该对象相关的等待池中,同时释放了锁对象,等待期间可以调用里面的同步方法,其他线程可以访问,等待时不拥有 CPU 的执行权,否则其他线程无法获取执行权。当一个线程执行了 wait() 方法后,必须调用 notify 或者 notifyAll 方法才能唤醒,而且是随机唤醒,若是被其他线程抢到了 CPU 执行权,该线程会继续进入等待状态。由于锁对象可以是任意对象,所以 wait() 方法必须定义在 Object 类中,因为 Obeject 类是所有类的基类。


作用范围

sleep() 是静态方法,也就是说它只对当前对象有效。通过 对象名.sleep() 想让该对象线程进入休眠是无效的,它只会让当前线程进入休眠。
wait 、 notify 和 notifyAll 方法只能在同步方法或者同步代码块中使用,而 sleep 方法可以在任何地方使用。
关于 notify 和 notifyAll 详解请查看后文(第九章、第十章)。


调用者的区别

sleep() 方法是让某个线程暂停运行一段时间,其控制范围是由当前线程决定,运行的主动权是由当前线程来控制(拥有 CPU 的执行权)。
wait() 方法是使一个线程进入等待状态,并且释放其所持有的锁对象,notify 方法是通知等待该锁对象的线程重新获得锁对象,然而如果没有获得锁对象,wait 方法和 notify 方法都是没有意义的,因此必须先获得锁对象再对锁对象进行进一步操作于是才要把 wait 方法和 notify 方法写到同步方法和同步代码块中了。所以 wait 、 notify 和 notifyAll 方法要和 synchronized 关键字一起使用。由此可知 wait 和 notify 、 notifyAll 方法是由确定的对象即锁对象来调用的,锁对象就像一个传话的人,他对某个线程说停下来等待,然后对另一个线程说你可以执行了(实质上是被捕获了),这一过程是线程通信。


本质区别

其实两者的区别都是让线程暂停运行一段时间,但本质的区别:

  • sleep() 是线程的运行状态控制
  • wait() 是线程间的通信。

关于线程间的通信详解请查看后文(第九章、第十章)。