19.wait与sleep的区别
wait与sleep的区别
引言
本节介绍wait方法与sleep方法的区别,一共有7件不同
位置
首先来看第一点位置,sleep方法是线程方法,它位于thread内里面,而wait方法是锁方法,它位于object类里面,
这里展示的是sleep方法锁处的位置以及方法个数。
同样的这里展示的是wait方法锁处的位置以及方法个数。
第二点
下面再来看第二点,是否需要当前线程拥有锁,调用sleep方法时,不需要当前线程拥有锁而调用wait方法时,则需要当前线程拥有锁。
现在看sleep方法实例,这里使当前线程休眠一秒钟,
package com.chenjie.executor.day19; import com.chenjie.executor.day18.Task; /** * * * @author chenjie * @version JDK 8 * @className Main1 (此处以class为例) * @date 2024/5/27 * @description TODO */ public class Main { /** * * @param args */ public static void main(String[] args) { try { Thread.sleep(1000L); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("人人都是程序员"); } }
从执行结果来看,调用sleep方法时,它不需要当前线程拥有锁。
再来看wait方法实例,这里使当前线程等待。
package com.chenjie.executor.day19; /** * * * @author chenjie * @version JDK 8 * @className Main1 (此处以class为例) * @date 2024/5/27 * @description TODO */ public class Main1 { /** * * @param args */ public static void main(String[] args) { // synchronized (Main1.class){ try { Main1.class.wait(1000L); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("人人都是程序员"); // } } }
从执行结果来看,若当前线程没有拥有锁程序则会发生异常,
所以我们需要在同步中调用wait方法,让线程获取锁。
package com.chenjie.executor.day19; /** * * * @author chenjie * @version JDK 8 * @className Main1 (此处以class为例) * @date 2024/5/27 * @description TODO */ public class Main1 { /** * * @param args */ public static void main(String[] args) { synchronized (Main1.class){ try { Main1.class.wait(1000L); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("人人都是程序员"); } } }
从执行结果来看,线程被等待没有引发异常。
支持手动唤醒
下面再来看第三点,是否支持手动唤醒?
sleep方法不支持手动唤醒,而wait方法是支持手动唤醒的,
支持的方法有 notify,notifyall由于sleep方法不支持手动唤醒,所以这里就不再演示它了。
下面只演示wait方法的实例,自定义一个任务,任务内容,就是使当前线程等待,等待之后,输出一句话执行该任务,并调用锁对象task的notify和notifyall方法唤醒线程。
package com.chenjie.executor.day19; import com.chenjie.executor.day18.Task; /** * * * @author chenjie * @version JDK 8 * @className Main1 (此处以class为例) * @date 2024/5/27 * @description TODO */ public class Main2 { /** * * @param args */ public static void main(String[] args) { Task task=new Task(); Thread thread = new Thread(task,"thread"); thread.start(); try { Thread.sleep(1000L); } catch (InterruptedException e) { throw new RuntimeException(e); } synchronized(task){ task.notify(); } } }
从执行结果来看,线程等待一秒后被唤醒。
是否支持自动唤醒
下面再来看第四点,是否支持自动唤醒,两个方法都支持自动唤醒,都可以指定超时时间。
先来看sleep方法实例,这里使当前线程休眠一秒钟。
package com.chenjie.executor.day19; import com.chenjie.executor.day18.Task; /** * * * @author chenjie * @version JDK 8 * @className Main1 (此处以class为例) * @date 2024/5/27 * @description TODO */ public class Main { /** * * @param args */ public static void main(String[] args) { try { Thread.sleep(1000L); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("人人都是程序员"); } }
从执行结果来看,程序经过一秒钟之后输出该内容。
再来看wait方法实例,这里使当前线程等待并指定超时时间为一秒钟。
package com.chenjie.executor.day19; /** * * * @author chenjie * @version JDK 8 * @className Main1 (此处以class为例) * @date 2024/5/27 * @description TODO */ public class Main1 { /** * * @param args */ public static void main(String[] args) { synchronized (Main1.class){ try { Main1.class.wait(1000L); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("人人都是程序员"); } } }
从执行结果来看,程序经过一秒钟之后输出该内容。
是否支持中断
下面我们来看第五点,是否支持中断。sleep方法和wait方法都支持中断,也就是支持interrupt方法,只不过他们被中断以后都会发生线程中断异常。
下面来看一下示例代码。首先来看sleep方法实例,制定一个任务,任务内容就是使当前线程休眠一秒钟,
package com.chenjie.executor.day19; /** * packageName com.chenjie.executor.day14 * * @author chenjie * @version JDK 8 * @className TicketTask (此处以class为例) * @date 2024/5/28 * @description TODO */ public class Task1 implements Runnable { @Override public void run() { try { Thread.sleep(1000L); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("人人都是程序员"); } }
然后执行该任务,接着中断执行任务的线程。从执行结果来看,线程休眠后立马被中断并引发了异常。
再来看wait方法实例,任务内容变成了使当前线程等待执行任务的步骤不变。下面来看看执行结果。
package com.chenjie.executor.day19; /** * packageName com.chenjie.executor.day14 * * @author chenjie * @version JDK 8 * @className TicketTask (此处以class为例) * @date 2024/5/28 * @description TODO */ public class Task implements Runnable { @Override public void run() { synchronized (this) { try { this.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("人人都是程序员"); } } }
从执行结果来看,线程等待后立马被中断,并引发了线程中断异常。
是否释放锁
下面我们来看第六点,是否释放锁?这里说的是当方法被调用时,此时锁是否被释放?
sleep方法被调用时不会释放速,而wait方法被调用时会立即释放锁。
先来看看sleep方法实例,制定一个任务,任务内容是使当前线程休眠三秒钟,
package com.chenjie.executor.day19; /** * packageName com.chenjie.executor.day14 * * @author chenjie * @version JDK 8 * @className TicketTask (此处以class为例) * @date 2024/5/28 * @description TODO */ public class Task2 implements Runnable { @Override public void run() { synchronized (this){// 添加同步块 try { Thread.sleep(3000L); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(System.currentTimeMillis()+"人人都是程序员"); } } }
然后去执行该任务,这里使主线程去争夺thread的线程的锁。
package com.chenjie.executor.day19; /** * * * @author chenjie * @version JDK 8 * @className Main1 (此处以class为例) * @date 2024/5/27 * @description TODO */ public class Main6 { /** * * @param args */ public static void main(String[] args) throws InterruptedException { Task2 task=new Task2(); Thread thread = new Thread(task,"thread"); thread.start(); Thread.sleep(100L); synchronized (task){ System.out.println("人人都是程序员1"); } } }
从执行结果来看,三秒后内容才被输出,说明调用sleep方法时不会释放锁。
再来看wait方法实例,任务内容变成使当前线程等待,其他的不变。
package com.chenjie.executor.day19; /** * packageName com.chenjie.executor.day14 * * @author chenjie * @version JDK 8 * @className TicketTask (此处以class为例) * @date 2024/5/28 * @description TODO */ public class Task3 implements Runnable { @Override public void run() { synchronized (this) { try { this.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("人人都是程序员"); } } }
从执行结果来看,内容立马被输出,说明调用wait方法会立即释放锁。main方法没有结束的原因是还有线程在等待
线程状态
下面我们再来看最后一点,线程状态,sleep方法它只有一种状态,timed_waiting,而wait方法它有两种状态,waiting和timed_waiting
为什么wait会有两种状态?因为wait一共有三个方法,其中第一个方法是手动唤醒,其余两个是超时自动唤醒,前者的线程状态是waiting,后者线程的状态是timed_waiting。
先来看sleep方法实例,任务还是使当前线程休眠三秒钟,执行任务。
package com.chenjie.executor.day19; /** * * * @author chenjie * @version JDK 8 * @className Main1 (此处以class为例) * @date 2024/5/27 * @description TODO */ public class Main8 { /** * * @param args */ public static void main(String[] args) throws InterruptedException { Task2 task=new Task2(); Thread thread = new Thread(task,"thread"); thread.start(); Thread.sleep(1000L); System.out.println(thread.getState()); } }
下面来看看执行结果。从执行结果来看,休眠中的线程,它的状态是timed_waiting,
再来看看wait的方法实例,它有两种现成状态,现在演示第一种线程状态,任务内容变成使当前线程等待其他的不变。
package com.chenjie.executor.day19; /** * packageName com.chenjie.executor.day14 * * @author chenjie * @version JDK 8 * @className TicketTask (此处以class为例) * @date 2024/5/28 * @description TODO */ public class Task implements Runnable { @Override public void run() { synchronized (this) { try { this.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("人人都是程序员"); } } }
下面来看一下执行结果,从执行结果来看,等待中的线程它的状态是waiting。
package com.chenjie.executor.day19; /** * * * @author chenjie * @version JDK 8 * @className Main1 (此处以class为例) * @date 2024/5/27 * @description TODO */ public class Main9 { /** * * @param args */ public static void main(String[] args) throws InterruptedException { Task task=new Task(); Thread thread = new Thread(task,"thread"); thread.start(); Thread.sleep(1000L); System.out.println(thread.getState()); } }
再看wait的第二种状态测试,等待超时时间为三秒钟,其他的不变。
package com.chenjie.executor.day19; /** * packageName com.chenjie.executor.day14 * * @author chenjie * @version JDK 8 * @className TicketTask (此处以class为例) * @date 2024/5/28 * @description TODO */ public class Task4 implements Runnable { @Override public void run() { synchronized (this) { try { this.wait(3000L); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("人人都是程序员"); } } }
下面来看一下执行结果。从执行结果来看,超时等待中的线程他的状态是timed_waiting。
总结
最后我们来总结一下本节的内容。本节介绍了wait方法和sleep方法的区别,总结了7点不同,这里就不再赘述了。大家可以截屏保存,以供日后使用。
本文来自博客园,作者:小陈子博客,转载请注明原文链接:https://www.cnblogs.com/cj8357475/p/16086051.html