java 线程问题

SuperCoderJz 2018-01-16 08:22:16
程序a
public class VolatileThread extends  Thread {
private int count = 1;

public void setCount(int count){
this.count = count;
}

public void run() {
System.out.println("进入run方法");
while(count >0){
// count++;
//System.out.println(Thread.currentThread().getName() + " count= " + count);
// System.out.println("123");
}
System.out.println("线程停止");
}

public static void main(String[] args) throws InterruptedException {
VolatileThread vt1 = new VolatileThread();
vt1.start();
Thread.sleep(1000);
vt1.setCount(-1);
}
}
结果
进入run方法

程序B
public class VolatileThread extends  Thread {
private int count = 1;

public void setCount(int count){
this.count = count;
}

public void run() {
System.out.println("进入run方法");
while(count >0){
// count++;
//System.out.println(Thread.currentThread().getName() + " count= " + count);
System.out.println("123");
}
System.out.println("线程停止");
}

public static void main(String[] args) throws InterruptedException {
VolatileThread vt1 = new VolatileThread();
vt1.start();
Thread.sleep(10);
vt1.setCount(-1);
}
}
结果
进入run方法
123
123
123
123
123
123
123
123
线程停止

为什么程序b比程序a只是多了一条print语句就可以正确退出,然而程序a一直在运行部能正常退出
...全文
1238 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
datadev_sh 2018-01-18
  • 打赏
  • 举报
回复
2、从指令重排序角度分析

datadev_sh 2018-01-17
  • 打赏
  • 举报
回复
引用 7 楼 weixin_39670158 的回复:
你的Java程序是一个进程 包括两个线程(main线程和VolatileThread 线程) 当CPU资源轮到Java程序的时候,这两个线程是由JVM调度的。 JVM是怎样调度的呢?抢占式调度:让可运行池中优先级高的线程拥有CPU使用权,若可运行池中线程优先级一样则随机选择线程。 因此,理论上讲:不加syso也是可以停下的,只是因为JVM一直选择VolatileThread线程。 回到楼主的问题 我的回答是:因为JVM就是让VolatileThread线程跑,没让main线程跑。 要让循环停下的话,我这里提供两种方法 1. 调用.setPriority()方法设置线程优先级 不推荐 2 使用 volatile关键字 推荐!
你没运行代码吧,运行下代码你就知道了,main线程已经结束了,但是run方法线程还在运行。
datadev_sh 2018-01-17
  • 打赏
  • 举报
回复
从“内存可见性”角度考虑。
从串行化执行来看,最终A线程应该停止执行。
每个线程会把数据缓存在本地内存,
DemoA中,主线程改变了count的值,但是run方法线程没有及时读取到这个值。

还有就是,DemoB多了几个字节码指令,不知道是否与那几个指令有关系


weixin_39670158 2018-01-17
  • 打赏
  • 举报
回复
你的Java程序是一个进程 包括两个线程(main线程和VolatileThread 线程) 当CPU资源轮到Java程序的时候,这两个线程是由JVM调度的。 JVM是怎样调度的呢?抢占式调度:让可运行池中优先级高的线程拥有CPU使用权,若可运行池中线程优先级一样则随机选择线程。 因此,理论上讲:不加syso也是可以停下的,只是因为JVM一直选择VolatileThread线程。 回到楼主的问题 我的回答是:因为JVM就是让VolatileThread线程跑,没让main线程跑。 要让循环停下的话,我这里提供两种方法 1. 调用.setPriority()方法设置线程优先级 不推荐 2 使用 volatile关键字 推荐!
dgqjava 2018-01-17
  • 打赏
  • 举报
回复
为了验证我说的 可以把你的System.out.println改成synchronized(System.out) {}这个空语句块 结果也是一样能正常结束的
dgqjava 2018-01-17
  • 打赏
  • 举报
回复
System.out.println内部调用PrintStream的println方法
    public void println(String x) {
        synchronized (this) {
            print(x);
            newLine();
        }
    }
该方法中有同步操作 同步操作的内存语义和volatile关键字类似 会对内存可见性产生影响(当然在内存模型中保证可见性的应该是不同线程对同一个监视器的获取和释放, 严格来说这样是确保可见性的充分条件但是根据底层实现的不同却未必是必要条件, 因此就算只是单个线程中有类似这种操作也可能改变内存可见性, 只不过在规范中不做保证而已) 另一方面打印操作属于是会对外部产生可见的影响的操作 因为用户可以在控制台看见打印出来的内容 这类操作在内存模型中也是有一些特殊对待的 例如不会被重排序 所以也可能会对多线程运行效果产生不可预测的影响
galiniur0u 2018-01-17
  • 打赏
  • 举报
回复
应该是java运行环境对while做了优化,导致while一直读取的是寄存器中的count值,而没有读取真实的count值。不知道楼主的机器是否是32位的,据说32位可以使用client模式运行程序,就可以正常退出。我的机器是64位的,不能使用client模式运行程序。 楼主还可以使用volatile关键字,使while始终读取最新的count值。
SuperCoderJz 2018-01-16
  • 打赏
  • 举报
回复
引用 1 楼 oyljerry 的回复:
把count设置为volatile类型。
这个我知道 但是为什么代码b 加了一句没什么用的print 结果就不一样了呢
oyljerry 2018-01-16
  • 打赏
  • 举报
回复
把count设置为volatile类型。

62,615

社区成员

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

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