概要: 学习使用Thread.currentThread()
了解中断线程的方法 了解sleep
方法抛出异常
Thread.currentThread()
Thread.currentThread()
方法可返回代码正在被哪个线程调用的信息。
public class Counter extends Thread {
//构造方法在主线程中被执行
public Counter() {
print("constructor begin");
print("Thread.currentThread().getName()------"+Thread.currentThread().getName());//main
print("this.getName()-----------"+this.getName());//Thread-0
print("constructor end");
}
@Override
public void run() {
//在子线程中被执行
print("run begin");
print("Thread.currentThread().getName()--------"+Thread.currentThread().getName());
print("this.getName()--------"+this.getName());
print("run end");
}
private void print(String msg){
System.out.println(msg);
}
}
public class Run {
public static void main(String[] args){
Counter counter = new Counter();
Thread t = new Thread(counter);
t.setName("new");
t.start();
}
}
/** 执行结果如下:
constructor begin
Thread.currentThread().getName()------main
this.getName()-----------Thread-0
constructor end
run begin
Thread.currentThread().getName()--------new
this.getName()--------Thread-0
run end
*/
复制代码
如上,Counter
构造方法是在main
线程中执行。run()
方法是在new
线程中执行的。
this.getName()
中this
指代的是Counter
实例,Counter
继承Thread
,在初始化会设置名称为Thread-0
。
第二个线程t
初始化,名称默认为Thread-1
,后续重新赋值为new
。
停止线程
有三种方法可以使终止线程。 1. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。 2. 使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)。 3. 使用interrupt方法中断线程。
interrupt()方法仅仅是在当前线程中打了一个停止的标记,并不是真的停止线程 换句话说,调用该方法的线程会被设置一个“中断”状态,用于判断的中断状态的方法如果返回true说明中断状态被设置了。
如何判断线程的状态是不是停止的?Thread.java
类里提供了两种方法: 1)this.interrupted()
: 测试当前线程是否已经是中断状态,执行后具有将状态标志置为false的功能。如果这个方法被连续调用两次,第二次调用将返回false。 2)this.isInterrupted()
: 测试线程Thread对象是否已经是中断状态,但不清除状态标识。
第一种方法,判断当前线程的状态;第二个方法,判断调用者的中断状态。
源码:
public classs Thread {
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
public boolean isInterrupted() {
return isInterrupted(false);
}
/**
* Tests if some Thread has been interrupted. The interrupted state
* is reset or not based on the value of ClearInterrupted that is
* passed.
*/
private native boolean isInterrupted(boolean ClearInterrupted);
}
复制代码
从源码中可以看出,最终调用的是isInterrupted(boolean ClearInterrupted)
方法,参数ClearInterrupted
可以控制中断状态清除。
验证1: 如下代码虽然调用了interrupted()方法,但是从运行结果来看,线程并未停止。
class MyThread extends Thread{
@Override
public void run() {
for(int i =0;i<1000;i++){
System.out.println("number"+i);
}
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
t.start();
//主线程运行10毫秒之后,中断子线程t。但是并没有效果。仅仅是打了一个标记
Thread.sleep(10);
t.interrupt();
}
}
复制代码
验证2: 从运行结果可以看出,t.interrupted()
返回的是当前线程的状态,即main
线程,main
从未调用过interrupt()
方法,未被标记过状态,因此返回的结果都是false
。
t.isInterrupted()
返回的是t线程的中断状态。主线程运行10毫秒之后,调用中断方法,此时返回状态为true
,表示t.interrupt()
方法生效了。
public class Run {
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
t.start();
//主线程运行10毫秒之后,中断子线程t。
Thread.sleep(10);
t.interrupt();
System.out.println("当前线程0:"+t.interrupted());
System.out.println("停止线程1:"+t.isInterrupted());
Thread.sleep(1000);
System.out.println("当前线程0:"+t.interrupted());
System.out.println("停止线程1:"+t.isInterrupted());
}
}
/**
当前线程0:false
停止线程1:true
当前线程0:false
停止线程1:false
*/
复制代码
验证3: 连续两次调用interrupted()
方法,第二次调用将返回false
public class Run {
public static void main(String[] args) throws InterruptedException {
Thread.currentThread().interrupt();
System.out.println("停止线程:"+Thread.currentThread().interrupted());
System.out.println("停止线程:"+Thread.currentThread().interrupted());
}
}
/**
停止线程:true
停止线程:false
*/
复制代码
应用 将interrupt()
方法和isInterrupted()
方法结合使用,来停止线程。
1.使用break停止线程
public class Counter0 extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 100000; i++) {
if(this.isInterrupted()){
System.out.println("已经标记了停止状态,我要退出");
break;
}
System.out.println("number"+i);
}
System.out.println("退出for循环,后面依然执行");
}
public class Run {
public static void main(String[] args){
try {
Counter0 counter0 = new Counter0();
counter0.start();
Thread.sleep(10);
counter0.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
number776
number777
number778
number779
number780
已经标记了停止状态,我要退出
退出for循环,后面依然执行
*/
复制代码
使用break
的方式并未完全退出子线程,for
循环之外的代码仍然在执行
改进:
2.使用抛异常的方式,停止线程执行
public class Counter0 extends Thread {
@Override
public void run() {
try{
for (int i = 0; i < 100000; i++) {
if(this.isInterrupted()){
System.out.println("已经标记了停止状态,我要退出");
throw new InterruptedException();
}
System.out.println("number"+i);
}
System.out.println("退出for循环,后面依然执行");
}catch (InterruptedException e){
System.out.println("捕获异常");
}
}
}
/**
number983
number984
number985
已经标记了停止状态,我要退出
捕获异常
*/
复制代码
在沉睡中停止线程
public class Thread implements Runnable{
/**
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified number of milliseconds, subject to
* the precision and accuracy of system timers and schedulers. The thread
* does not lose ownership of any monitors.
*
* @param millis
* the length of time to sleep in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public static native void sleep(long millis) throws InterruptedException;
}
复制代码
InterruptedException
当前线程睡眠中,如果有任何线程中断了当前线程,抛出异常。当抛出异常时,当前线程的中断状态被清除,值为false
举个栗子:
public class Counter0 extends Thread {
@Override
public void run() {
super.run();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println("状态标记:"+this.isInterrupted());
e.printStackTrace();
}
}
}
public class Run {
public static void main(String[] args){
try {
Counter0 counter0 = new Counter0();
counter0.start();
Thread.sleep(10);
counter0.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
状态标记:false
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.yolo.thread.Counter0.run(Counter0.java:37)
*/
复制代码