下面我们来学习下Thread.sleep()函数,它的签名 如下
public static native void sleep (long mills) throws InterruptedException
Thread.sleep()方法会让当前线程休眠若干时间,它会抛出一个interruptedException的异常,interruptedException不是运行时异常,也就是说程序必须捕获并且处理它,当线程在sleep()休眠的时候,如果被中断了,这个异常就会产生。
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread() {
@Override
public void run() {
while (true) {
if (Thread.currentThread().isInterrupted()) { // 判断线程是否被中断
System.out.println("霖霖提醒您,该线程已经被中断了");
break;
}
try {
Thread.sleep(2000); // 将线程休眠2秒,线程被中断,则程序会抛出异常,继续往下执行,在catch中捕获中断
} catch (InterruptedException e) {
System.out.println("霖霖提示,当线程休眠的时候被中断");// 但是我们没有立即退出异常,而是进行了后续的处理,置上中断标志
// 我们在这里设置中断状态
Thread.currentThread().interrupt();
}
Thread.yield();
}
}
};
t1.start();
Thread.sleep(2000);
t1.interrupt();
}
运行结果如下:
Thread.sleep()方法由于中断而抛出异常,此时,它会清除中断标记,如果不加处理,那么在下一次循环开始时,就无法捕获这个中断,所以在异常处理中,再次设置中断标记。
2.2.4 等待(wait) 和通知(notify)
为了支持多线程之间的协作,JDK提供了两个重要的接口线程等待和通知,这两个方法不在Thread中,而是属于Object类,也就意味着任何一个对象都可以调用这两个方法。
方法签名介绍:
public final void wait () throwsInterruptException
public final native void notify ()
当一个对象调用了wait()方法,当前线程就会在这个对象上等待,就会停止执行,转为等待状态,那么等待到合适结束呢?
线程一直等待到其他线程调用了notify方法为止,这时该对象就成为多个线程之间的有效通信手段。如果一个线程调用了obj.wait(),那么它就会进入object对象的等待队列,在这个等待的队列中可能会有多个线程,因为系统运行多个线程同时等待某一个对象。当obj.notify()被调用时,他就会从这个 等待的队列中随机选择一个线程,将其唤醒,在这里的选择是不公平的,和先后顺序无关,是一个随机的选择。
除了notify方法外,还有一个notifyAll()的方法,它和notify方法功能基本一致,不同的是该方法唤醒的是等待队列中的所有等级的线程,而不是随机选择一个。
这里强调一下,wait()方法不要随意调用,它必须包含在所以synchronized语句中,无论是wait()或者notify()都需要首先获得目标对象的监视器,如下所示:
t1 线程 t2 线程
取得监视器---->object.wait()----->释放object监视器 取得object监视器---->object.notify()--->释放object监视器
等待object监视器-->重获object监视器-->继续执行
package cn.xuetao.test;
public class Test0223 {
final static Object object = new Object();
public static class T1 extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println(System.currentTimeMillis()+"霖霖提醒您,T1 start");
try {
System.out.println(System.currentTimeMillis()+"霖霖提醒您 ,T1 wait for object");
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis()+"霖霖提醒您,T1 end");
}
}
}
public static class T2 extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println(System.currentTimeMillis()+"霖霖提醒您,T2 start! notify one thread");
object.notify();
System.out.println(System.currentTimeMillis()+"霖霖提醒您,T2 end");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
Thread t1 = new T1();
Thread t2 = new T2();
t1.start();
t2.start();
}
}
运行结果:
注意这个时间戳信息,可以看到,在T2通知T1继续执行后,T1并不能立即继续执行,而是要等待T2释放object锁,并重新成功获得锁后,才能继续执行,因此这里间隔2秒(因为T2休眠了2秒)
注意:Object.wait()和 Thread.sleep()方法都可以让线程等待若干时间,除了wait()方法可以被唤醒之外,另一个主要的区别在于wait()方法会释放目标对象的锁,而Thread.sleep()方法不会释放任何资源。