while循环修改条件后没法跳出的疑惑(已解决)

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

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

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。spa

其中的while换成for,do-while都是同样的结果线程

经过询问他人,虽然没有弄明白发生的缘由。可是他提出了一个解决办法。code

在程序中内存

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

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

很奇怪

更新: Java内存模型规定:同步

  1. 共享变量必须保存在主内存中
  2. 线程有本身的工做内存,线程只能够操做本身的工做内存
  3. 线程要操做共享变量,须要从主内存中读取到工做内存,修改后需从工做内存同步到主内存中。

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

  1. volatile关键字:
    volatile语意:it

    • 使用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传过来的值写入到主内存的共享变量中。

这些操做都是原子性,可是操做之间不是原子性。

相关文章
相关标签/搜索