对于线程来说,动起来不是什么问题,但是如何让它停下来,就需要一些处理。
虽然stop、suspend、resume都可以使线程停下来,但是官方是不建议的,现在已经废弃了。
interrupt方法仅仅只是打了一个停止标记。
判断线程是否停止状态
- interrupt
- isInterrupted
public class Test148 {
public static void main(String[] args) {
MyThread33 mm = new MyThread33();
Thread t = new Thread(mm);
t.start();
t.interrupt();
System.out.println("Thread.currentThread().interrupted()"+Thread.currentThread().interrupted());//当前运行的是main,故false
System.out.println("t.interrupted()"+t.interrupted());
System.out.println("Thread.currentThread().isInterrupted()"+Thread.currentThread().isInterrupted());
System.out.println("t.isInterrupted()"+t.isInterrupted());//对线程t判断是否中断状态,true。
}
}
class MyThread33 extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0;i<10000;i++) {
System.out.println("*");
}
}
}
运行结果如下:
我们来分析一下,我们给线程t设置停止标志,interrupted方法,只是对当前正在运行的线程,判断是否中断状态,它不管调用对象;isInterrupted,是针对调用线程对象,来判断是否中断状态。
修改上述代码:
Thread.currentThread().interrupt();//我们给main线程设置中断标志
System.out.println("Thread.currentThread().interrupted()"+Thread.currentThread().interrupted());
System.out.println("Thread.currentThread().interrupted()"+Thread.currentThread().interrupted());
我们发现执行下来,第一个是true,因为当前的正在运行的线程对象是main,第二个是false,这里实际上,执行interrupt,如果是中断状态,会自动清除,所以是false。而isInterrupted,就不具备清除中断标志。验证代码修改如下:
t.interrupt();
System.out.println("t.isInterrupted()"+t.isInterrupted());//true
System.out.println("t.isInterrupted()"+t.isInterrupted());//true
牛刀小试
看看结合上面讲的如何让线程停下来。
public class Test148 {
public static void main(String[] args) {
MyThread33 mm = new MyThread33();
Thread t = new Thread(mm);
t.start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.interrupt();
}
}
class MyThread33 extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0;i<10000;i++) {
//interrupted 上面讲过是针对当前正在运行的线程,判断是否有中断标志,这里的this,指的是
//MyThread33线程的实例,也就是mm。但是这时正在运行时线程t,
//看谁调用start。interrupted又不管谁调用,它只在现在正在运行的
System.out.println(this.getName());//Thread-0
if(Thread.currentThread().interrupted()) {
System.out.println("我要停止了");
break;
}
System.out.println(i);
}
}
}
在上面代码,还存在一个问题,就是如果for循环外面还有语句,那么这样的话,下面的语句还是会执行。在上面的代码做修改:
try {
for(int i = 0;i<10000;i++) {
//interrupted 上面讲过是针对当前正在运行的线程,判断是否有中断标志,这里的this,指的是
//MyThread33线程的实例,也就是mm。但是这时正在运行时线程t,
//看谁调用start。interrupted又不管谁调用,它只在现在正在运行的
System.out.println(this.getName());//Thread-0
if(Thread.currentThread().interrupted()) {
System.out.println("我要停止了");
throw new InterruptedException();
}
System.out.println(i);
}
System.out.println("我在for外面");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
我们把执行体中需要执行的代码,放到一个异常的try中,当捕获这个异常的时候,程序代码是try中是不会往下执行,处理上面的问题,但是异常程序会让程序崩了。
线程在Sleep中停止
在这个操作中,一定要保证线程在Sleep的状态下,你去给他设置了停止标志,才会触发异常,如果Sleep状态结束,主线程才执行t.interrupt(),是不会影响的。
MyTask111 mt = new MyTask111();
Thread t = new Thread(mt);
t.start();
/*try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
t.interrupt();
}
}
class MyTask111 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
System.out.println("我停止了");
e.printStackTrace();
}
}
}
我们之前就说过,Java已经抛弃stop方法,为啥呢,使用该方法停止线程,会造成数据不一致的问题,只要执行stop语句,是不管线程执行到哪,它立马停止。下面模拟该问题的发生。
public class Account {
private String username="a";
private String userpassword = "aa";
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUserpasswword() {
return userpassword;
}
public void setUserpasswword(String userpasswword) {
this.userpassword = userpasswword;
}
public String toString(String username,String userpassword) {
this.username = username;
try {
Thread.sleep(3000);//通过睡眠拖时间,给时间让主线程执行到stop
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.userpassword = userpassword;
return username+" "+userpassword;
}
}
public class Test159 {
public static void main(String[] args) {
Account a = new Account();
MyThread990 mt = new MyThread990(a);
Thread t = new Thread(mt);
t.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.stop();
System.out.println(a.getUsername()+" "+a.getUserpasswword());
}
}
class MyThread990 implements Runnable{
private Account useraccound;
public MyThread990(Account useraccound) {
super();
this.useraccound = useraccound;
}
@Override
public void run() {
// TODO Auto-generated method stub
useraccound.toString("b","bb");
}
}
上述结果是b aa ,可见执行属性值修改的时候,userpassword 并没有执行到,就stop了。
上面讲过来使用异常配合interrupt来停止异常,下面可以使用return加interrupt也可以实现。
public class Test160 {
public static void main(String[] args) {
Thread t = new Thread(new MyThread55());
t.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.interrupt();
}
}
class MyThread55 implements Runnable{
int i = 0;
@Override
public void run() {
// TODO Auto-generated method stub
while(true) {
System.out.println(i++);
if(Thread.interrupted()) {
return;
}
}
}
}