V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
lithium148
V2EX  ›  问与答

为什么是 1?这行代码的结果

  •  
  •   lithium148 · 2023-02-02 18:28:37 +08:00 · 1043 次点击
    这是一个创建于 663 天前的主题,其中的信息可能已经有所发展或是发生改变。

    简单描述下代码:

    static 变量 i

    线程 1:尝试把 i 设为 1

    线程 2:尝试把 i 设为 2 ,如果 i 为 1 ,print i

    不断运行线程 1 和 2

    public class Main {
    
        // static 变量 i
        static volatile Integer i = 0;
    
        public static void main(String[] args) throws Exception {
    
            // 线程 1
            Thread thread1 = new Thread(()->{
                synchronized(i) {
                    try {
    
                        i = 1;
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
    
            // 线程 2
            Thread thread2 = new Thread(()->{
                synchronized (i) {
                    try {
    
                        i = 2;
                        Thread.sleep(100);
                        if (i == 1) {
                            System.out.println("1"); // 实际运行结果为 1
                        }
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
    
            // 不断运行线程 1 和 2
            while (true) {
                new Thread(thread1).start();
                new Thread(thread2).start();
            }
        }
    }
    
    

    为什么运行的结果是 1

    还请各位大佬不吝赐教(抱拳),

    谢谢各位大哥

    7 条回复    2023-02-03 10:47:01 +08:00
    RedBeanIce
        1
    RedBeanIce  
       2023-02-02 19:29:07 +08:00
    import java.util.concurrent.atomic.AtomicLong;

    public class VolatileTest1 {

    private static final AtomicLong THREAD1_COUNT = new AtomicLong(0);
    private static final AtomicLong THREAD2_COUNT = new AtomicLong(0);

    // static 变量 i
    static volatile Integer i = 0;

    public static void main(String[] args) throws Exception {

    // 线程 1
    Thread thread1 = new Thread(() -> {
    synchronized (i) {
    try {

    i = 1;
    Thread.sleep(100);
    THREAD1_COUNT.incrementAndGet();
    } catch (InterruptedException e) {
    throw new RuntimeException(e);
    }
    }
    });

    // 线程 2
    Thread thread2 = new Thread(() -> {
    synchronized (i) {
    try {

    i = 2;
    Thread.sleep(100);
    if (i == 1) {
    System.out.println("1"); // 实际运行结果为 1
    System.out.println("thread1 运行次数" + THREAD1_COUNT.get());
    System.out.println("thread2 运行次数" + THREAD2_COUNT.get());
    }
    THREAD2_COUNT.incrementAndGet();
    } catch (InterruptedException e) {
    throw new RuntimeException(e);
    }
    }
    });

    // 不断运行线程 1 和 2
    while (true) {
    new Thread(thread1).start();
    new Thread(thread2).start();
    }
    }
    }



    要不你试试这个,,看看
    kkkbbb
        2
    kkkbbb  
       2023-02-02 19:30:58 +08:00
    只有等于 1 才打印啊
    hefish
        3
    hefish  
       2023-02-02 19:32:05 +08:00
    按我的理解,sleep 了啊,然后把时间片给别人了啊,然后别人设了个 1 ,然后别人 sleep ,然后轮到你检测 i 了。
    Nooooobycat
        4
    Nooooobycat  
       2023-02-02 19:39:57 +08:00
    你线程 2 把 Integer 的值改掉之后,值为 1 的 Integer 对象锁还是在线程 2 上,线程 1 此时也可以进入 synchronized 代码块(获取到的是值为 2 的 Integer 对象的锁,然后又改回 1 。然后紧接着线程 2 就执行到了 if 语句并输出了
    Jooooooooo
        5
    Jooooooooo  
       2023-02-02 19:41:57 +08:00
    你用一个对象装着 i, 然后锁那个对象.
    hhjswf
        6
    hhjswf  
       2023-02-03 01:51:36 +08:00 via Android
    @hefish sleep 不会释放锁
    hefish
        7
    hefish  
       2023-02-03 10:47:01 +08:00
    @hhjswf 哦。。原来是这样。。我这个业务不熟悉那。。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2691 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 15:42 · PVG 23:42 · LAX 07:42 · JFK 10:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.