线程中使用标志位来中断线程,线程一直运行

z1340954953 2017-06-17 06:29:04

public class ThreadDemo1 implements Runnable{
public static void main(String[] args) throws InterruptedException {
ThreadDemo1 t1 = new ThreadDemo1();
Thread t = new Thread(t1, "thread1");
t.start();
Thread.currentThread().sleep(10);
t1.cancel();
System.out.println("检查线程的运行状态标志flag:"+t1.flag);
System.out.println(t.getName()+" is interrupt: "+t.isInterrupted());

}
boolean flag = true;
int i=0;
@Override
public void run() {
System.out.println("thread运行状态:"+flag);
while(flag){

i++;
}
System.out.println("输出结果: i= "+i);
}
public void cancel(){
flag = false;
}
}


这样的输出结果:

thread运行状态:true
检查线程的运行状态标志flag:false
thread1 is interrupt: false

提问:
为什么调用cancel方法,flag=false,线程的run方法不会输出结果,而且虚拟机一直在跑,
...全文
419 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
z1340954953 2017-06-18
  • 打赏
  • 举报
回复
谢谢大家的解答!
HinanaiTenshi 2017-06-17
  • 打赏
  • 举报
回复
典型的多线程Happens-before Order问题,参考java语言规范-Happens-before Order。 针对这个demo而言,java1.5之后的规范推荐的解决方法是在共享属性前增加参数volatile
A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.
也就是把12行变成
volatile boolean flag = true;
这个问题看似简单,实际上水很深。当初阿里dubbo框架开发组的leader梁飞发现即使在阿里巴巴相对精锐的团队里,也有很多兄弟对此一头雾水,他不得不开课来培训这个问题。 lz如果是初学者,可以先跳过这个问题,先记住多线程下公共属性的并发的套路,等打好了基础再回头来学习这个问题。
qwqwqw408 2017-06-17
  • 打赏
  • 举报
回复
在类型前面加上volatile 关键字,就可以了。
soton_dolphin 2017-06-17
  • 打赏
  • 举报
回复


public class ThreadDemo1 implements Runnable{

    private int counter;
    private boolean flag = true;

    public synchronized boolean getFlag(){
        return this.flag;
    }

    public synchronized void increaseCounter(){
        counter ++;
    }


    public static void main(String[] args) throws InterruptedException {
        ThreadDemo1 t1 = new ThreadDemo1();
        Thread t = new Thread(t1, "thread1");
        t.start();
        Thread.currentThread().sleep(10);
        t1.cancel();
        System.out.println("检查线程的运行状态标志flag:"+t1.flag);
        System.out.println(t.getName()+" is interrupt: "+t.isInterrupted());

    }
    @Override
    public void run() {
        System.out.println("thread运行状态:"+flag);
        while(getFlag()){

            increaseCounter();
        }
        System.out.println("输出结果:  i= "+ this.counter);
    }
    public synchronized void cancel(){
        flag = false;
    }
}
qwqwqw408 2017-06-17
  • 打赏
  • 举报
回复
看了java的标准文档,是所有非daemon 线程退出,程序才会退出。所以应该是2楼说的情况
qwqwqw408 2017-06-17
  • 打赏
  • 举报
回复
Thread.currentThread().sleep(1000);改为t1.join();会好一点
qwqwqw408 2017-06-17
  • 打赏
  • 举报
回复
应该是main方法里面调用t1.cancel();输出2行信息之后就立即结束了,导致程序退出,所以t1也不会执行了。至于你说的虚拟机还在,不知道你是以什么方式怎么运行的这个程序。你可以在System.out.println(t.getName()+" is interrupt: "+t.isInterrupted());后面加个Thread.currentThread().sleep(1000);,应该就能看到t1最后的那个输出了。
丄whistle 2017-06-17
  • 打赏
  • 举报
回复
引用大神博客回答,链接:http://blog.csdn.net/smarttony/article/details/2073715 因为在java的多线程模型中,有一个公共的对象存储区,但是每个对象都有自己的私有备份,当一个线程改变了状态,jvm并不能保证这个线程改变过的变量即时更新公共对象存储区的状态,可能造成问题。 可能是由于没有得到更新后的flag;导致while无限循环。 可以通过加锁的方式得到更新结果。 synchronized boolean getFlag() { return flag; } @Override public void run() { System.out.println("thread运行状态:" + flag); while (getFlag()) { i++; } System.out.println("输出结果: i= " + i); } 将flag加锁后,输出没有出现问题。
soton_dolphin 2017-06-17
  • 打赏
  • 举报
回复
你需要用synchronized 去控制线程的交互。把线程共享的变量放到synchronized 块里面

62,628

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧