博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
while循环修改条件后无法跳出的疑惑(已解决)
阅读量:5957 次
发布时间:2019-06-19

本文共 1475 字,大约阅读时间需要 4 分钟。

最近在编写项目的时候使用while遇到了一个奇怪的问题。我在使用异步调用的时候主线程某一个方法需要等待异步返回才能被调用,因此我设定了一个boolean,当异步返回时修改条件然后在主线程的方法中加入while来长时间遍历以等待异步返回。

这里我将代码省略只保留主要:

public static void main(String[] args) {    Task task = new Task();    new Thread(task).start();    try {        Thread.sleep(3000);    } catch (Exception e) {}    task.close();}class Task implements Runnable {    private int i = 1;        public void run() {        while (i == 1){}        System.out.println("跳出循环");    }        public void close() {        i = 2;    }}复制代码

Task启动后会在while中死循环,主线程等待3s后将i修改成2,但是task中的while没有跳出,即 i == 1 条件还是为true。

其中的while换成for,do-while都是一样的结果

通过询问他人,虽然没有弄明白发生的原因。但是他提出了一个解决办法。

在程序中

while(i == 1){}复制代码

会过多占用CPU,因此使用Thread.yield()来将CPU资源让步给其他线程。当while中加入这个之后就能达到我需要的效果了。

很奇怪

更新: Java内存模型规定:

  1. 共享变量必须保存在主内存中
  2. 线程有自己的工作内存,线程只可以操作自己的工作内存
  3. 线程要操作共享变量,需要从主内存中读取到工作内存,修改后需从工作内存同步到主内存中。

这三点直接就点名了错误的原因。解决办法有两个:

  1. volatile关键字:

    volatile语意:

    • 使用volatile变量时,必须重新从主内存加载,并read、load是连续的。
    • 修改volatile变量后,必须立马同步回主内存,并且store、write是连续的。

    缺点:volatile只能保证线程的变量可见性。但是它没有锁机制,所以无法避免多个线程同时访问公共变量。

    优点:编写简单。

  2. synchronized关键字

    synchronized语意:

    • 进入同步块前,先清空工作内存的共享变量,再从主内存重新加载,同时获取该共享资源的锁。
    • 修改后必须先将共享变量同步回主内存中才能释放锁。

    优点:有加锁机制,保护共享资源。

补充 - 内存协议:

Java内存协议规定了8中原子操作:

  1. lock(锁定):将主内存的变量锁定,为一线个线程独占。
  2. unlock(解锁):将lock加的锁解除。
  3. read(读取):作用于主内存变量,将主内存的变量放入寄存器中。
  4. load(载入):作用于工作内存,将寄存器中的主内存变量传递给线程的工作内存。
  5. use(使用):作用于工作内存,将值传递给线程的代码执行引擎。
  6. assign(赋值):作用于工作内存,将执行引擎处理返回的值重新赋值给寄存器。
  7. store(存入):将寄存器中的变量传入主内存中。
  8. write(写入):作用于主内存变量,将store传过来的值写入到主内存的共享变量中。

这些操作都是原子性,但是操作之间不是原子性。

转载地址:http://obgxx.baihongyu.com/

你可能感兴趣的文章
HDU2586 How far away ?(LCA模板题)
查看>>
点我吧工作总结(技术篇) Velocity
查看>>
IOS-线程(GCD)
查看>>
Ehcache详细解读(转)
查看>>
Android游戏之平台接入的一点记录
查看>>
源码编译php5.4 ./configure参数
查看>>
13、Cocos2dx 3.0游戏开发找小三之3.0中的Director :郝萌主,一统江湖
查看>>
超人学院Hadoop大数据技术资源分享
查看>>
Oracle迁移:Linux->Windows
查看>>
【转】利用mybatis-generator自动生成代码
查看>>
C# 将MSMQ消息转换成Json格式 【优化】
查看>>
传纸条(一)(双线程dp)
查看>>
bootstrap精简教程
查看>>
【转】c++继承:公有、私有、保护
查看>>
实现经常使用的配置文件/初始化文件读取的一个C程序
查看>>
Intellij idea断点 Debugger slow: Method breakpoints my dramatically slow down debugging
查看>>
第一个JSP程序
查看>>
ubuntu16.4中开启vncserver进行远程桌面
查看>>
shell-IF判断
查看>>
【转】Maven实战(九)---模块聚合和继承
查看>>