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

2023-02-02 18:28:37 +08:00
 lithium148

简单描述下代码:

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

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

谢谢各位大哥

954 次点击
所在节点    问与答
7 条回复
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
2023-02-02 19:30:58 +08:00
只有等于 1 才打印啊
hefish
2023-02-02 19:32:05 +08:00
按我的理解,sleep 了啊,然后把时间片给别人了啊,然后别人设了个 1 ,然后别人 sleep ,然后轮到你检测 i 了。
Nooooobycat
2023-02-02 19:39:57 +08:00
你线程 2 把 Integer 的值改掉之后,值为 1 的 Integer 对象锁还是在线程 2 上,线程 1 此时也可以进入 synchronized 代码块(获取到的是值为 2 的 Integer 对象的锁,然后又改回 1 。然后紧接着线程 2 就执行到了 if 语句并输出了
Jooooooooo
2023-02-02 19:41:57 +08:00
你用一个对象装着 i, 然后锁那个对象.
hhjswf
2023-02-03 01:51:36 +08:00
@hefish sleep 不会释放锁
hefish
2023-02-03 10:47:01 +08:00
@hhjswf 哦。。原来是这样。。我这个业务不熟悉那。。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/912668

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX