新人问一下 Java 多线程的问题。 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
waiaan
V2EX    Java

新人问一下 Java 多线程的问题。

  •  
  •   waiaan Nov 30, 2020 2895 views
    This topic created in 1980 days ago, the information mentioned may be changed or developed.
     class Hero { private String name; public int hp = 10; public Hero(String str) { this.name = str; } public synchronized void recover() { this.hp += 1; } public synchronized void hurt() { this.hp -= 1; } } public class Test { public static void main(String[] args) { Hero garen = new Hero("garen"); // 线程一 new Thread(() -> { System.out.println(Thread.currentThread().getName() + "...."); while (true) { while (garen.hp == 1) { continue; } try { Thread.sleep(200); garen.hurt(); System.out.println(Thread.currentThread().getName() + "..." + "hp down-" + garen.hp); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); // 线程二 new Thread(() -> { while (true) { if (garen.hp == 20) { continue; } try { Thread.sleep(400); garen.recover(); System.out.println(Thread.currentThread().getName() + "....." + "hp up-" + (garen.hp)); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); } } 

    为什么线程一不执行了?是因为没有更新 garen.hp 的值吗?

    13 replies    2020-11-30 22:19:36 +08:00
    Joooooooo
        1
    Jooooooooo  
       Nov 30, 2020
    hp 没有 volatile, 线程一是有可能死在 while(hp == 1) 这一行上. 它看见的 hp 值一直都是 1.
    killy
        2
    killy  
       Nov 30, 2020
    hp 变量加个 volatile 修饰符试试
    waiaan
        3
    waiaan  
    OP
       Nov 30, 2020
    @Jooooooooo
    @killy
    加 volatile 是可以的,但是为什么线程一的 hp 没同步?或者多线程这种数据同步的时机是在什么时候?
    谢谢。
    Jooooooooo
        4
    Jooooooooo  
       Nov 30, 2020
    @waiaan 如果不加 volatile, 那行为是未定义. 啥时候同步看底层硬件的具体实现.

    严格讲, 这个时候线程一所跑的那个 cpu 去读 hp 这个值时一直用的是 cpu 自身寄存器(或者缓存)里的值, 这个值什么时候会去和 L1 cache/主内存同步各个硬件实现不一样
    waiaan
        5
    waiaan  
    OP
       Nov 30, 2020
    @Jooooooooo 有这方面的资料或者讲解吗?我想看一下。谢谢。
    Jooooooooo
        6
    Jooooooooo  
       Nov 30, 2020
    @waiaan 这个比较接近底层我也不知道有啥相关系统性的书能看. 可以先看这个

    gee.cs.oswego.edu/dl/jmm/cookbook.html

    然后从中寻找关键词搜索更多的文章看
    summertimesad
        7
    summertimesad  
       Nov 30, 2020
    @waiaan 建议先看看 Java 的内存模型了解一下。volatile 会强制刷新线程的本地内存到主内存中,这样可以保证 Happens-Before,我以前写个一篇博客大致总结了一下,你看看先[JMM]( https://blog.csdn.net/panyongcsd/article/details/84311387)
    nicoley
        8
    nicoley  
       Nov 30, 2020
    加 volatile 修饰符就是保证共享变量在不同线程中的可见性。数据同步发生时机我认为是当其中一个线程对共享变量进行了更新操作,那么另外一个线程将会实时看到共享变量的变化。
    waiaan
        9
    waiaan  
    OP
       Nov 30, 2020
    @nicoley
    没加 volatile 修饰符,另一个线程并没有实时更新变量值。
    anansi
        10
    anansi  
       Nov 30, 2020
    这不是 cache locally 吗。。。不同线程对共享资源的读取并不是瞬时同步的。volatile 也只是权宜之计,对于复杂对象并不能够保证立即刷新,这就引出了为什么线程间通信是如此的重要。。
    waiaan
        11
    waiaan  
    OP
       Nov 30, 2020
    @Jooooooooo
    @rambo92
    多谢。
    nlzy
        12
    nlzy  
       Nov 30, 2020
    @waiaan #5 《深入理解 Java 虚拟机》这本书里有。
    hdfg159
        13
    hdfg159  
       Nov 30, 2020 via Android
    hahah,如果你是代码块锁对象,就不用加 volatile
    About     Help     Advertise     Blog     API     FAQ     Solana     896 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 45ms UTC 23:04 PVG 07:04 LAX 16:04 JFK 19:04
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86