当我们刚学完Thread一个线程t1之后,迫不及待地键入t1.start()开始启动线程,肯定思考过如何将这个线程停下来
其实原理只有一个,那就是让run方法结束
要知道开启多线程运行,其运行代码通常都是循环结构,只要控制住循环就可以让run方法结合苏,也就是线程结束
比如写个代码
class StopThread implements Runnable {
public synchronized void run()
{
while(true)
{
System.out.println(Thread.currentThread().getName()+"...run");
}
}
}
public class StopThreadDemo {
public static void main(String[] args) {
StopThread st=new StopThread();
Thread t1=new Thread(st);
Thread t2=new Thread(st);
t1.start();
t2.start();
int num=0;
while(true)
{
if(num++==60)
{
break;
}
System.out.println(Thread.currentThread().getName()+"......"+num);
}
}
}
这个小程序很简单,就是让两个线程一直跑,跑到60次之后就break,想法是好的,这个程序我是不会去跑的,因为我知道这个是无限循环,while(true)这个标记让它一直转
所以如果while(true)这个标记能够控制住,这个小程序就能停下来
- 可以定义个flag=true,再定义个changeFlag()方法,这个方法里面将flag切换为false
将while(true)改为while(false) - 如果num++=60,就调用changeFlag方法
class StopThread implements Runnable {
private boolean flag=true;//**************
public void run()
{
while(flag)//**************
{
System.out.println(Thread.currentThread().getName()+"...run");
}
}
public void changeFlag()//**************
{
flag=false;
}
}
public class StopThreadDemo {
public static void main(String[] args) {
StopThread st=new StopThread();
Thread t1=new Thread(st);
Thread t2=new Thread(st);
t1.start();
t2.start();
int num=0;
while(true)
{
if(num++==60)
{
st.changeFlag();//**************
break;
}
System.out.println(Thread.currentThread().getName()+"......"+num);
}
}
}
但是有一种情况,程序也停不下来
就是同步
public synchronized void run()
{
while(flag)//**************
{
try {
wait();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"...Exception");
flag=false;
}
System.out.println(Thread.currentThread().getName()+"...run");
}
}
*run()方法若是同步函数,且在while内try一个wait(),抛出InterruptedException,这时候运行也做了changeFlag()改变,程序就不会停下来;
如图,程序没有停下来,但是并不占用资源,不是死循环,因为wait在那儿了
- 当主线程while(true)的时候一直在转,到num==60的时候,st.changeFlag()也读了。可是开启两个线程之后,无论什么时候抢到CPU资源,都去public
synchronized void run(){}里面去运行 - Thread-0进去之后,拿到一把锁,然后wait()了,放弃了资格,然后Thread-1进去也释放资格了,然后这两个都挂在这儿不动了;
- 主线程执行完了,还有两个线程存活,这个就是问题,改变了标记flag但是没有结束线程
也就是当线程处于冻结状态,就不会读取到标记,那么线程就不会结束。
**只有wait()结束之后再去while(flag)循环,读到标记才能结束。
我们可以强制做这件事情
在Thread中提供了一个方法叫interrupt()方法,叫做中断线程:如果线程在调用Object类的wait()等方法,或者join和sleep受阻,则其终端状态江北清除;中断状态也就是Wait,还会收到一个InterruptException;但是中断并不是stop,只是挂起
这时候,我可以强制清除其中断状态,强制地恢复到运行状态
wait就像是催眠,催眠师拿个表将他吹眠之后进入中断状态,随后又用他的方法把他叫醒了;但现在,催眠师又把他催眠到中断状态,然后出国了。。。这时候要他醒过来怎么办,我又不会催眠师的方法,那我就一砖头下去把他呼醒得了
但是受伤了,发生异常了
现在对t1和t2下手,改变主函数的if内部:
if(num++=60)
{
t1.interrupt();
t2.interrupt();
st.changeFlag();
break;
}
完整如下:
class StopThread implements Runnable {
private boolean flag=true;
public synchronized void run()
{
while(flag)
{
try {
wait();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"...Exception");
//flag=false;
}
System.out.println(Thread.currentThread().getName()+"...run");
}
}
public void changeFlag()
{
flag=false;
}
}
public class StopThreadDemo {
public static void main(String[] args) {
StopThread st=new StopThread();
Thread t1=new Thread(st);
Thread t2=new Thread(st);
t1.start();
t2.start();
int num=0;
while(true)
{
if(num++==60)
{
t1.interrupt();
//st.changeFlag();
break;
}
System.out.println(Thread.currentThread().getName()+"......"+num);
}
System.out.println("over");
}
}
看打印结果,Thread-0出现了终端异常,这就是因为t1的中断状态被强制清除了,所以产生了中断异常,但是程序还挂着不动,可以看到catch到异常之后又处理了一次,打印了Thread_0…run,之后此线程又回到了while(flag), 此时flag依旧为true,接着wait,又挂了
所以知道这个原因之后就很好解决了,
也就是只要发生异常,就代表有人在强制清除其中断状态,那么就在处理这个异常的时候,将flag标记为false,就可以完美结束了。
class StopThread implements Runnable {
private boolean flag=true;
public synchronized void run()
{
while(flag)
{
try {
wait();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"...Exception");
flag=false;
}
System.out.println(Thread.currentThread().getName()+"...run");
}
}
public void changeFlag()
{
flag = false;
}
}
public class StopThreadDemo {
public static void main(String[] args) {
StopThread st=new StopThread();
Thread t1=new Thread(st);
Thread t2=new Thread(st);
t1.start();
t2.start();
int num=0;
while(true)
{
if(num++==60)
{
t1.interrupt();
t2.interrupt();
st.changeFlag();
break;
}
System.out.println(Thread.currentThread().getName()+"......"+num);
}
System.out.println("over");
}
}
总结就是
当没有指定的方法让冻结的线程恢复到运行状态时,这就需要对冻结进行清除
强制让线程恢复到运行状态中来,就可以操作标记flag,让线程结束Thread类提供该方法,interrupt( );