println导致的线程缓冲区刷新|一个volatile引起的思考 问题的解决

此文转载自:https://blog.csdn.net/weixin_44494373/article/details/111767803#commentBox
问题引出:

今天在看volatile的时候,自己写了个例子,
发现即使没有volatile,我程序也照常跑了

描述

首先看看这个情况的描述

第一个代码是有关何时以及如何使用volatile的示例,熟悉volatile的一定知道,为了使程序成功运行,我们需要添加volatile。

第二个代码表示,即使没有volatile,该程序情景仍然可以成功运行。

第一段代码, 经典的volatile使用案例


public static int num=1;

public static class MyThread extends Thread {
    // flag
    private boolean flag = false ;
    public boolean isFlag() { return flag;}
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) { e.printStackTrace();
        }
// change flag to true
        this.flag = true ;
        System.out.println("flag=" + flag);
        this.flag=true;
    }
}
// main函数
static void testWithOutVolatile(){
    MyThread t=new MyThread();
    t.start();
    while(true) {
        boolean is=t.flag;
        if (is) {
            System.out.println("run======");
        }
    }
}

启动后,除非使用volatile,否则主线程将找不到flag变量的更改
println导致的线程缓冲区刷新|一个volatile引起的思考
问题的解决

但是如果下面这段代码,程序他,竟然看到了flag的变动

static int amb=0;
static void testSimple(){
    Thread t1=new Thread(()->{
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        amb++;
    });
    Thread t2=new Thread(()->{while(true) {
        if (amb == 0) {
            System.out.println("no");
        }
        if (amb != 0) {
            System.out.println("SUc");
            break;
        }
    }});
    t2.start();
    t1.start();
}

自己动手修改了一下代码尝试了一下,
发现如果删除print,线程就看不到变化,
只要随随便便加一个print语句,线程就看到了变化

Thread t2=new Thread(()->{while(true) {
        System.out.println("no");
        if (amb != 0) {
            System.out.println("SUc");
            break;
        }
    }});

println导致的线程缓冲区刷新|一个volatile引起的思考
问题的解决

问题似乎变的清晰了,点开print的代码,

 public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

这里有一个synchronized ,synchronized大家都知道吧,重量级锁,线程将释放资源等待
线程执行到这里时,释放了自己的资源,发生了“线程切换”,线程的缓冲区就随之消失,
等到第二次执行到这里的时候,重新获取了变量的值
所以看起来似乎不用使用“volatile”

更多文章,看https://blog.csdn.net/weixin_44494373