作者|雷哥来源|Java面试真题解析(ID:aimianshi666)转载请联系授权(微信ID:GG_Stone)在Java中,让线程休眠的方法有很多种,这些方法大致可以分为两类,一类是设置时间和一段时间后自动唤醒,而另一个类提供了一对睡眠和唤醒方法。线程休眠后,可以随时唤醒线程。PS:休眠是指暂停一个线程的执行(进入等待状态),唤醒是指让一个暂停的线程继续执行。线程休眠有五个方法:Thread.sleepTimeUnitwaitConditionLockSupport其中sleep和TimeUnit用于在休眠一段时间后自动唤醒一个线程,而wait、Condition和LockSupport提供一对休眠和唤醒线程的方法,即可以随时唤醒一个线程的线程。方法一:Thread.sleepThread.sleep方法来自Thread类。它是一种本机本地方法。其实现源码如下:publicstaticnativevoidsleep(longmillis)throwsInterruptedException;Thread.sleep方法需要传一个long类型的milliseconds,表示n毫秒后自动唤醒。它的基本用法如下:Threadt1=newThread(){@Overridepublicvoidrun(){System.out.println("Threadexecution:"+LocalDateTime.now());尝试{Thread.sleep(1000);}catch(InterruptedExceptione){e.printStackTrace();}System.out.println("线程结束:"+LocalDateTime.now());}};t1.start();上面程序的执行结果如下图所示:方法二:因为TimeUnitsleep方法需要传一个毫秒类型的参数,设置大一点的时间比较麻烦,比如设置1小时或者1天,那么我们可以使用TimeUnit来代替sleep方法来实现睡眠。TimeUnit的作用和sleep一样,让线程休眠N个时间单位后自动唤醒。它的基本用法如下:Threadt1=newThread(){@Overridepublicvoidrun(){System.out.println("Threadexecution:"+LocalDateTime.now());尝试{TimeUnit.SECONDS.sleep(1);//睡眠1s//TimeUnit.DAYS.sleep(1);//休眠1天}catch(InterruptedExceptione){e.printStackTrace();}System.out.println("线程结束:"+LocalDateTime.now());}};t1.start();上述程序的执行结果如下图所示:当我们查看TimeUnit源码时,会发现其底层是基于Thread.sleep方法实现的,其实现源码如下:方法三:waitwait/notify/notifyAll来自Object类,其中:wait()/wait(longtimeout):表示让当前线程进入休眠状态。notify():唤醒当前对象上休眠的线程。notifyAll():唤醒当前对象上所有休眠的线程。其中wait()方法表示让当前线程无限等待,直到遇到notify/notifyAll方法才会被唤醒,wait(longtimeout)表示接收long类型的超时时间,如果没有遇到notify/notifyAll,会在长毫秒后自动唤醒,遇到notify/notifyAll方法会立即唤醒。它的基本用法如下:Objectlock=newObject();newThread(()->{synchronized(lock){try{//让当前线程休眠lock.wait();}catch(InterruptedExceptione){e.printStackTrace();}}}).start();synchronized(lock){lock.notify();//唤醒当前对象上的休眠线程//lock.notifyAll();//唤醒当前对象Thread上所有休眠的线程}需要注意的是wait/notify/notifyAll使用时必须和synchronized一起使用,否则程序执行时会报错。方法四:作为wait的升级版,ConditionCondition提供了以下常用方法:await():让当前线程进入等待状态,直到收到通知(信号)或中断后才会继续执行。awaitUninterruptibly():让当前线程进入等待状态,直到收到通知才会被唤醒。它不响应线程的中断通知。await(longtime,TimeUnitunit):在await()方法的基础上增加了超时时间。如果超过超时时间没有遇到wakeup方法,会自动唤醒并继续执行。awaitUntil(Datedeadline):让当前线程进入等待状态。如果没有遇到唤醒方式,会在设定的时间后自动唤醒。signal():唤醒一个等待Condition的线程。signalAll():唤醒所有等待Condition的线程。它的基本用法如下:{publicstaticvoidmain(String[]args)throwsInterruptedException{//创建一个锁finalLocklock=newReentrantLock();//创建一个条件finalConditioncondition=lock.newCondition();newThread(()->{System.out.println("Threadexecution:"+LocalDateTime.now());lock.lock();//获取锁try{//睡眠线程condition.await();}catch(InterruptedExceptione){e.printStackTrace();}finally{lock.unlock();//释放锁}System.out.println("Threadended:"+LocalDateTime.now());}).开始();线程.睡眠(1000);锁.lock();//获取锁try{//唤醒线程condition.signal();}最后{lock.unlock();//释放锁}}}1000);锁.锁();//获取锁try{//唤醒线程condition.signal();}最后{lock.unlock();//释放锁}}}与wait方法相比,Condition对象更加灵活,因为它可以在一个锁上定义多个Condition对象以供使用,如下代码所示://创建一个锁finalLocklock=newReentrantLock();//CreateCondition1finalConditioncondition=lock.newCondition();//CreateCondition2finalConditioncondition2=lock.newCondition();//...方法五:LockSupportLockSupport为底层运行线程Sleep和唤醒对象,它提供了两种常用方法:LockSupport.park():休眠当前线程LockSupport.unpark(Threadthread):唤醒指定线程。它的基本用法如下:Threadt1=newThread(()->{System.out.println("Thread1sleep");LockSupport.park();//sleepthreadSystem.out.println("Thread1执行End");},"Thread1");t1.start();Threadt2=newThread(()->{System.out.println("Thread2Sleep");LockSupport.park();//休眠线程System.out.println("线程2执行结束");},"线程2");t2.start();Threadt3=newThread(()->{try{Thread.sleep(1000);}catch(InterruptedExceptione){e.printStackTrace();}System.out.println("唤醒线程1");LockSupport.unpark(t1);//唤醒线程1},"线程3");t3.开始();上面程序的执行结果如下图所示:总结Thread.sleep和TimeUnit是让线程在一段时间后自动休眠和唤醒,而wait、Condition和LockSupport提供休眠和唤醒的方法线程,其中Condition是wait方法的升级版,而LockSupport是更底层的让线程休眠和唤醒的方法。它可以唤醒指定的线程,这是其他方法(函数)所没有的。
