请教一个简单的多线程问题

撸猫最开心 2020-07-17 01:37:28

public class Test {
public static boolean stop;

public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
int i=0;
while (!stop)
i++;
});
System.out.println("1");
TimeUnit.SECONDS.sleep(1);
System.out.println("1");
stop=true;
}
}


简单来说一个静态的变量stop,乍看之下stop的值被改了,线程应该停止才对,但实际运行的时候并没有,stop的值并没有被同步
想请教下这是为什么,静态变量的话不是应该都能读取到才对么
...全文
7837 点赞 收藏 16
写回复
16 条回复
撸猫最开心 2020年07月22日
引用 15 楼 即心即佛 的回复:
加volatile试试 public static volatile boolean stop;
谢谢老哥,我只是看到一个错误例子拿出来请求下原因而已 加volatile是可以解决这个问题的
回复 点赞
即心即佛 2020年07月21日
加volatile试试 public static volatile boolean stop;
回复 点赞
撸猫最开心 2020年07月20日
引用 10 楼 Ja先生 的回复:
难道我执行结果和你执行结果不一样么,i大概跑到250000左右结束,给变量加volatile关键字大概220000左右结束,主线程休眠大概200000左右结束,子线程休眠直接结束。我想应该主线程代码执行的时间子线程得跑的飞快吧,执行到200000也不足为奇,主线程休眠时间i减少了不知道怎么解释,子线程休眠的话直接结束,主线程也执行到stop=true了,状态也变完了,直接结束了
老兄你是不是在子线程的循环里加了打印语句啊? 感觉是在子线程循环里随便加个啥都正常结束 但是如果只有一句i++没别的了,我等了一分钟多种都不会结束
回复 点赞
撸猫最开心 2020年07月20日
引用 13 楼 dkwuxiang 的回复:
不是随便加个什么都可以, 是 System.out 和 线程休眠, 会导致 释放对CPU的占用 ,让CPU 有时间刷新副本缓存
原来如此,感谢指教
回复 点赞
dkwuxiang 2020年07月20日
不是随便加个什么都可以, 是 System.out 和 线程休眠, 会导致 释放对CPU的占用 ,让CPU 有时间刷新副本缓存
回复 点赞
qq_39936465 2020年07月20日
引用 11 楼 撸猫最开心 的回复:
老兄你是不是在子线程的循环里加了打印语句啊? 感觉是在子线程循环里随便加个啥都正常结束 但是如果只有一句i++没别的了,我等了一分钟多种都不会结束
你只要了解同步,就是知道你的程序为什么不会结束了。主程序和线程是2段程序,不会因为主程序的变量值变化而变。同步就是为了让线程的变量跟着主程序的变量值保持一致。
回复 点赞
Forevermark993 2020年07月17日
引用 5 楼 撸猫最开心 的回复:
[quote=引用 3 楼 Farmermark993 的回复:]多核执行线程,涉及到cpu高速缓存问题。 cpu <——> 高速缓存 <———> 内存 1.启动线程,从物理内存读取一份到高速缓存中,此时stop是false,!stop为true,并循环执行 2.接下来执行,main线程从物理内存读取stop后更改成true,但此时stop并不保证写入物理内存的时效,此时另外一个线程的stop取的一直是false。因此会在这里导致循环不能退出,这里是一个典型的并发可见性问题。可以用volatile关键字修饰变量,保证修改后,强制写入物理内存,保证对另外一个线程的可见
感谢老哥 另外请教下在多线程中,是不是使用了静态变量都会这样? 之前使用静态没注意过这种问题,突然看到有点转不过弯[/quote]并不是,之所这里一直没有退出是因为你的main线程执行stop=true;就结束了,可能还没来得及急写入物理线程就结束了,如果接下来有返回,休眠等等操作,给时间写入就不会出现这个问题,你可以试试在stop=true;后面在休眠几秒,看看作用
回复 点赞
撸猫最开心 2020年07月17日
引用 3 楼 Farmermark993 的回复:
多核执行线程,涉及到cpu高速缓存问题。 cpu <——> 高速缓存 <———> 内存 1.启动线程,从物理内存读取一份到高速缓存中,此时stop是false,!stop为true,并循环执行 2.接下来执行,main线程从物理内存读取stop后更改成true,但此时stop并不保证写入物理内存的时效,此时另外一个线程的stop取的一直是false。因此会在这里导致循环不能退出,这里是一个典型的并发可见性问题。可以用volatile关键字修饰变量,保证修改后,强制写入物理内存,保证对另外一个线程的可见
感谢老哥 另外请教下在多线程中,是不是使用了静态变量都会这样? 之前使用静态没注意过这种问题,突然看到有点转不过弯
回复 点赞
撸猫最开心 2020年07月17日
引用 1 楼 医手 的回复:
其实你的线程都没启动过,你怎么知道线程没停止呢?
不好意思啊,贴代码的时候误删了一句,线程是启动了的

public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            int i=0;
            while (!stop)
                i++;
        });
        thread.start();
        System.out.println("1");
        TimeUnit.SECONDS.sleep(1);
        System.out.println("1");
        stop=true;
    }
回复 点赞
Forevermark993 2020年07月17日
多核执行线程,涉及到cpu高速缓存问题。 cpu <——> 高速缓存 <———> 内存 1.启动线程,从物理内存读取一份到高速缓存中,此时stop是false,!stop为true,并循环执行 2.接下来执行,main线程从物理内存读取stop后更改成true,但此时stop并不保证写入物理内存的时效,此时另外一个线程的stop取的一直是false。因此会在这里导致循环不能退出,这里是一个典型的并发可见性问题。可以用volatile关键字修饰变量,保证修改后,强制写入物理内存,保证对另外一个线程的可见
回复 点赞
何为岸 2020年07月17日
引用 1 楼 医手 的回复:
其实你的线程都没启动过,你怎么知道线程没停止呢?
哈哈 老哥扎心了
回复 点赞
医手 2020年07月17日
其实你的线程都没启动过,你怎么知道线程没停止呢?
回复 点赞
Ja先生 2020年07月17日
难道我执行结果和你执行结果不一样么,i大概跑到250000左右结束,给变量加volatile关键字大概220000左右结束,主线程休眠大概200000左右结束,子线程休眠直接结束。我想应该主线程代码执行的时间子线程得跑的飞快吧,执行到200000也不足为奇,主线程休眠时间i减少了不知道怎么解释,子线程休眠的话直接结束,主线程也执行到stop=true了,状态也变完了,直接结束了
回复 点赞
ITjavaman 2020年07月17日

    public static boolean stop;

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            long i=0;
            while (!stop) {
                i++;
                if(i==10000000000L){
                }
            }
            System.out.println("end"+i);
        });
        thread.start();
        System.out.println("1");
        TimeUnit.SECONDS.sleep(1);
        System.out.println("1");
        stop=true;
    }
抛个砖引下玉 (1)按上面代码,stop又变成可见了 (2)楼主的源代码,指定启动参数-Xint 解释模式运行,stop也可见了
回复 点赞
撸猫最开心 2020年07月17日
引用 6 楼 Farmermark993 的回复:
[quote=引用 5 楼 撸猫最开心 的回复:][quote=引用 3 楼 Farmermark993 的回复:]多核执行线程,涉及到cpu高速缓存问题。 cpu <——> 高速缓存 <———> 内存 1.启动线程,从物理内存读取一份到高速缓存中,此时stop是false,!stop为true,并循环执行 2.接下来执行,main线程从物理内存读取stop后更改成true,但此时stop并不保证写入物理内存的时效,此时另外一个线程的stop取的一直是false。因此会在这里导致循环不能退出,这里是一个典型的并发可见性问题。可以用volatile关键字修饰变量,保证修改后,强制写入物理内存,保证对另外一个线程的可见
感谢老哥 另外请教下在多线程中,是不是使用了静态变量都会这样? 之前使用静态没注意过这种问题,突然看到有点转不过弯[/quote]并不是,之所这里一直没有退出是因为你的main线程执行stop=true;就结束了,可能还没来得及急写入物理线程就结束了,如果接下来有返回,休眠等等操作,给时间写入就不会出现这个问题,你可以试试在stop=true;后面在休眠几秒,看看作用[/quote] 非常感谢 试下了在主线程里stop=true后,增加个休眠几秒或者再多做一些操作,结果都是一样的 倒是在子线程的while循环里增加休眠1毫秒,就能正常结束了,猜测可能是之前子线程里一直不停的循环,高速的使用stop导致无法更新,于是给个休息时间就有时间去更新同步了?
回复 点赞
烟花散尽13141 2020年07月17日
3楼说的很有道理
回复 点赞
发动态
发帖子
Java SE
创建于2007-09-28

3.4w+

社区成员

30.7w+

社区内容

Java 2 Standard Edition
社区公告
暂无公告