-1

B thread reads two global variables, A thread writes two global variables.

How could second much bigger than first?

public class ThreadTest {
    private static volatile int first = 0;
    private static volatile int second = 0;

    private static class ReaderThread extends Thread {
        @Override
        public void run() {
            while (first < 10000) {
                if (first != second) {
                    System.out.println("ThreadB------first = " + first + ", second = " + second);
                }
            }
            System.out.println("ThreadB------first = " + first + ", second = " + second);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new ReaderThread().start();
        Thread.sleep(1000L);
        while (first < 10000){
            first++;
            second++;
        }
    }
}
ThreadB------first = 3296, second = 3535
ThreadB------first = 7615, second = 7663
ThreadB------first = 8179, second = 8192
ThreadB------first = 8635, second = 8662
ThreadB------first = 9151, second = 9177
ThreadB------first = 10000, second = 10000
ThreadB------first = 10000, second = 10000

So what happened, and how to fix this problem?

markspace
  • 10,621
  • 3
  • 25
  • 39
Karl.Li
  • 169
  • 12

1 Answers1

2

After the 'if' is satisfied, you execute some relatively slow-running string concatenations. Some unknown length of time (maybe hundreds of machine cycles) can elapse between reading 'first' and reading 'second' while evaluating, left to right, the expression for the argument to the println call.

Try recoding as

   int f = first, s = second;
   if (f != s) {
        System.out.println("ThreadB------first = " + f + ", second = " + s);
   }

and see what it looks like then.

The bigger issue is, if this is a fragment of some real code, it does not seem like it can provide any useful synchronization. Each integer has immediately-visible effects, but there is no synchronization between the two values. The only guarantee I can see is that, as written, you cannot ever see a value of 'second' that is less than the value of 'first'.

user14644949
  • 321
  • 1
  • 3
  • but how do you explain change `if (first != second)` to `if (first < second)` will still work – Karl.Li Nov 19 '20 at 02:21
  • `first > second` seems not possible, because second is incremented after first, and the `if` statement reads second after first. So I'd expect `first < second` and `first != second` to be equivalent. – user14644949 Nov 19 '20 at 02:24
  • In fact I want to repetition instruction rearrangement in jvm with `first` and `second`, and failed. – Karl.Li Nov 19 '20 at 02:40
  • Sorry, that sentence simply makes no sense. I tried `user14544949`'s answer and it worked. Please be specific. – markspace Nov 19 '20 at 02:49
  • what made you believe this: _you cannot ever see a value of 'second' that is less than the value of 'first'_? – Eugene Nov 19 '20 at 02:53
  • In the 'writer' thread, first is written before second. In the 'reader' thread, in particular in evaluation of the if-condition, second is read after first. An informal consideration of happens-before gives me the conclusion. I'm open to analysis that says I'm wrong, and now I think about it, I probably am in a strict sense (though I still suspect the OP will never see that case) but for me it would be entirely theoretical, since if I cared about the relationship between the two values. I'd skip the use of volatile and use some stronger synchronization. – user14644949 Nov 19 '20 at 02:58
  • 1) unless you tag me with `@`, I can't tell you commented. 2) you are correct about happens-before, with regards to `volatile`. In this particular case the semantics can be simplified to "volatiles _themselves_ are not re-ordered". 3) Not very sure I understand what you mean by relationship here, but if you mean _order_ `volatile` is the correct usage here. Note that increments are not atomic, so that is why the OP seems different results. – Eugene Nov 19 '20 at 03:09
  • @Eugene - I mean concerns such as the one the OP apparently has about whether 'second' is different to 'first', and/or whether 'second' is much larger than 'first'. For that sort of thing, skip the volatile and use something like 'synchronized'. But it's difficult to tell from the toy code presented whether this is an actual issue. – user14644949 Nov 19 '20 at 18:19