代码之家  ›  专栏  ›  技术社区  ›  user

Java中的同步-Java示例中的思考

  •  0
  • user  · 技术社区  · 8 年前

    我现在读了Java思考,关于同步的一章,有一个例子我不理解。

    public abstract class IntGenerator {
    
        private volatile boolean canceled = false;
    
        public abstract int next();
    
        public void cancel() {
            canceled = true;
        }
    
        public boolean isCanceled() {
            return canceled;
        }
    }
    
    public class EvenGenerator extends IntGenerator {
    
        private int currentEvenValue = 0;
    
        final Object object = new Object();
    
        @Override
        public int next() {
            ++currentEvenValue;
            ++currentEvenValue;
            return currentEvenValue;
        }
    
        public static void main(String[] args) {
            EvenChecker.test(new EvenGenerator());
        }
    }
    
    public class EvenChecker implements Runnable {
    
        private IntGenerator generator;
        private final int id;
    
        public EvenChecker(IntGenerator generator, int id) {
            this.generator = generator;
            this.id = id;
        }
    
        @Override
        public void run() {
            while (!generator.isCanceled()) {
                int val = generator.next();
                if (val % 2 != 0) {
                    System.out.println(val + " odd");
                    generator.cancel();
                }
            }
        }
    
        public static void test(IntGenerator generator, int count) {
            System.out.println("To finish press Ctrl + C");
            final ExecutorService executorService = Executors.newCachedThreadPool();
            for (int i = 0; i < count; i++) {
                executorService.execute(new EvenChecker(generator, i));
            }
        }
    
        public static void test(IntGenerator generator) {
            test(generator, 10);
        }
    }
    

    1239 odd
    1237 odd
    1239 odd
    

    我理解这一点。这意味着3个线程在第一次增量后读取currentValue。

    该问题的解决方案是:

    public class SynchronizedEvenGenerator extends IntGenerator {
    
        private int currentEvenValue = 0;
    
        @Override
        public synchronized int next() {
            ++currentEvenValue;
            Thread.yield();
            ++currentEvenValue;
            return currentEvenValue;
        }
    
        public static void main(String[] args) {
            EvenChecker.test(new SynchronizedEvenGenerator());
        }
    }
    

    现在,程序正在无限期地工作,没有错误。 我试图以这种方式仅同步增量:

    public class SynchronizedEvenGenerator extends IntGenerator {
    
        private int currentEvenValue = 0;
    
        @Override
        public int next() {
            synchronized (this) {
                ++currentEvenValue;
                Thread.yield();
                ++currentEvenValue;
            }
            return currentEvenValue;
        }
    
        public static void main(String[] args) {
            EvenChecker.test(new SynchronizedEvenGenerator());
        }
    }
    

    但现在的例子是:

    345 odd
    

    我无法理解,如果两个增量都是同步的,并且任何线程都无法读取第一个和第二个增量之间的currentValue,为什么可以读取currentValue的奇数值。

    为什么我得到这个输出。如何工作 synchronized ?

    2 回复  |  直到 8 年前
        1
  •  2
  •   Solomon Slow    8 年前

    最后一个例子 return currentEventValue; 语句不在 synchronized 块假设线程A和线程B都调用 next() :

    螺纹A:

    • 同步,
    • currentEventValue (现在的值为奇数)
    • 增量 (值再次为偶数)
    • 离开

    螺纹B:

    • 增量 currentEventValue (现在的值为奇数)

    螺纹A:

    • 退货 currentEventValue (奇数)

    螺纹B:

    • 增量 currentEventValue (值再次为偶数)
    • 离开 已同步
    • 返回偶数值。
        2
  •  1
  •   JB Nizet    8 年前
    • currentEvenValue为342
    • 线程1进入同步块
    • 线程2试图进入同步块,但必须等待
    • 线程1将currentEvenValue增加两次,因此该值现在为344
    • 线程1离开同步块
    • 线程1读取currentEvenValue的值,返回并打印:345

    规则很简单:对共享状态(读或写)的所有访问都必须同步。