V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
bee7
V2EX  ›  Java

求大佬解答一下关于两个线程交替打印奇偶数的问题

  •  
  •   bee7 · 2020-07-23 14:04:09 +08:00 · 2347 次点击
    这是一个创建于 1618 天前的主题,其中的信息可能已经有所发展或是发生改变。

    就是下面的代码是交替打印 0 到 100 的奇偶数,我这里的循环条件是 count 小于 100,为什么最后的输出结果会一直到 100 呢,不是 100 就跳出循环执行不到了吗,求大佬解答

    public class WaitNotifyPrintOddEvenSyn {
        private static int count;
        private static final Object lock = new Object();
        
        //新建 2 个线程,一个只处理偶数,一个只处理奇数
        //并且用 synchronized 来通信
        public static void main(String[] args) {        
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while(count < 100){
                        synchronized (lock){
                            if((count & 1) == 0){
                                System.out.println(Thread.currentThread().getName() + ": " + count);
                                count++;
                            }
                        }
                    }
                }
            }, "偶线程").start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while(count < 100){
                        synchronized (lock){
                            if((count & 1) == 1){
                                System.out.println(Thread.currentThread().getName() + ": " + count);
                                count++;
                            }
                        }
                    }
                }
            }, "奇线程").start();
        }
    }
    
    9 条回复    2020-07-29 16:23:34 +08:00
    popesaga
        1
    popesaga  
       2020-07-23 14:11:20 +08:00   ❤️ 2
    count++ 不是原子操作,再了解一下 volatile 和 AtomicInteger 。一个线程在做 count < 100 判断的时候读到了 99,然后才有另外一个线程的 count++ 引起的新值 100 更新的操作,再接着一个释放锁一个获得锁,100 就会被打印出来。
    sonice
        2
    sonice  
       2020-07-23 14:12:23 +08:00
    用 AtomicInteger
    araraloren
        3
    araraloren  
       2020-07-23 14:13:14 +08:00
    count 是 99 的时候可能让两个线程同时通过 while 条件。。
    bee7
        4
    bee7  
    OP
       2020-07-23 14:14:16 +08:00
    @popesaga 感谢大佬,懂了!!
    JasonLaw
        5
    JasonLaw  
       2020-07-23 15:07:54 +08:00   ❤️ 1
    @popesaga #1
    @bee7 #4

    count++本身不是原子操作,但是代码里已经使用了内置锁保证了 count++的原子性。根本问题不是 count++,而是没有用锁保护好 count 这个共享可变变量,也就是两个线程可以“同时”执行 count < 100 判断。如果当前 count 是 99,奇线程执行判断成功,获取锁,但是在更新 count 值之前,这个时候奇线程中止了,轮到偶线程执行,虽然判断成功,但是没办法获取锁,不过等到奇线程释放锁之后,偶线程就可以获取到锁了,最后偶线程会打印出 100 。
    eve1yb0dy
        6
    eve1yb0dy  
       2020-07-23 16:36:11 +08:00
    我关注楼主名字...起的有意思
    kkkkkrua
        7
    kkkkkrua  
       2020-07-23 16:38:07 +08:00
    这写法不过关啊,看看 Reentrantlock
    M1NGc
        8
    M1NGc  
       2020-07-24 15:45:05 +08:00
    用同步队列
    Octopvs
        9
    Octopvs  
       2020-07-29 16:23:34 +08:00
    用双重检查锁就可以,sync 前判断一次<100,sync 后再判断一次就好了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4377 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 10:06 · PVG 18:06 · LAX 02:06 · JFK 05:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.