1. 线程中断
Thread类提供了一种线程可以中断其他线程的机制。当一个线程被中断时,它会抛出java.lang.InterruptedException异常。这一机制由下面三种方法构成。
一个线程在未正常结束之前, 被强制终止是很危险的. 因为它可能带来完全预料不到的严重后果. 也因此Thread.suspend, Thread.stop等方法都弃用了。那么不能直接把一个线程搞挂掉, 但有时候又有必要让一个线程死掉, 或者让它结束某种等待的状态,优雅的方法就是, 给那个线程一个中断信号, 让它自己决定该怎么办
- void interrupt(): 中断调用此方法的Thread对象所关联的线程。
当一条线程由于调用了Thread的sleep()或者join()方法而被阻塞时,该线程的中断状态就会被清除,同时抛出InterruptedException异常。
- static boolean interrupted(): 验证当前线程是否已经中断,这个方法会清除掉线程的中断状态
- boolean isInterrupted(): 也是验证当前线程是否已经中断,但是不会清除中断状态
public class InterruptThread {
public static void main(String[] args) throws InterruptedException {
Runnable r = () -> {
// 中断当前线程
Thread.currentThread().interrupt();
// isInterrupted()方法不会清除中断状态
System.out.println(Thread.currentThread().isInterrupted());
// interrupted()方法是静态类方法,会清除中断状态
System.out.println(Thread.currentThread().interrupted());
System.out.println(Thread.currentThread().interrupted());
};
Thread t1 = new Thread(r, "t1");
t1.start();
}
}
# 结果显然如下
true
true
false
2. 线程等待
线程(如main主线程)有时候会启动另一个线程去操作单调的计算、下载文件等耗时操作。而调用工作的线程(如主线程)又需要等待这个工作线程执行结束,以处理其得到的结果(如计算结果)。
Thread类提供了3种重载join()方法,允许调用线程等待执行此方法的线程对象所关联的线程执行完毕。(即其他线程(如主线程)要等待调用了join方法的工作线程执行结束)
- void join(): 其他要无限期等待,直到调用该方法的线程死亡。当任意线程中断该线程的时候,会抛出InterruptedException,这个异常被抛出
- void join(long millis): 该线程死亡之前,其他最多等待millis毫秒。参数取负数抛出IllegalArgumentException异常,此外join(0) <=> join()。
- void join(long millis, int nanos): 要最多等待毫秒+纳秒。
public class JoinDemo {
private static int count = 0;
public static void main(String[] args) {
Runnable r = () -> {
System.out.println("处理工作线程的业务");
count ++;
};
Thread t1 = new Thread(r, "t1");
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
// 当这条工作线程被其他线程中断就会抛出InterruptedException异常
e.printStackTrace();
}
System.out.println("主线程等待工作线程结束然后处理结果: " + count);
}
}
调用了t1.join(),主线程要等待t1运行结束打印结果如下,也就是串行顺序执行。
处理工作线程的业务
主线程等待工作线程结束然后处理结果: 1
如果去掉。那么t1和主线程就会并发执行,结果基本都如下(t1线程从NEW状态到就绪的时候,系统调度主线程,然后才到t1线程获取到CPU资源执行run()方法的业务)
主线程等待工作线程结束然后处理结果: 0
处理工作线程的业务
3. 线程睡眠
Thread类声明了一对静态重载使线程休眠的方法。(暂时性地停止执行)。
- void sleep(long millies): 睡眠millis毫秒数。线程睡眠实际的毫秒数取决于系统定时器和调试器的精度。如果millis是负数,那么就会导致IllegalArgumentException被抛出。当任意线程中断了当前线程,就会导致InterruptedException被抛出,异常抛出,线程的中断状态就会被清除。
- void sleep(long millis, int nanos): 毫秒+纳秒。
sleep()方法相较于忙循环更好,因为它们不会浪处理器周期。
public class SleepDemo {
public static void main(String[] args) {
Runnable r = () -> {
String name = Thread.currentThread().getName();
int count = 0;
while (!Thread.interrupted()) {
System.out.println(name + ":" + count++);
}
};
Thread t1 = new Thread(r, "t1");
Thread t2 = new Thread(r, "t2");
t1.start();
t2.start();
try {
// 当前线程睡眠1millis
Thread.sleep(1);
} catch (InterruptedException e) {
//
}
t1.interrupt();
t2.interrupt();
}
}
主线程休眠1millis,t1和t2线程此时并发执行。结果的多少取决于系统。
t1:0
t1:1
t1:2
t1:3
t1:4
t1:5
t2:0
t1:6
t2:1
t1:7
t2:2
t1:8
...