1

I have the following code

import java.util.concurrent.*;
public class dsd {

 private static boolean stopRequested;
 private static void requestStop() {
  stopRequested = true;
 }
 private static synchronized boolean stopRequested() {
  return stopRequested;
 }
 public static void main(String[] args)
 throws InterruptedException {
  Thread backgroundThread = new Thread(new Runnable() {
   public void run() {
    int i = 0;
    while (!stopRequested())
     i++;
   }
  });
  backgroundThread.start();
  TimeUnit.SECONDS.sleep(1);
  requestStop();
 }
}

The question is why it works even if requestStop() is not synchronized? If I try to do the same thing to the stopRequested(), it doesn't work anymore. Why is there no problem with concurrency of the threads on that variable? I know that synchronization makes a variable appear in a consistent state by other threads. But here the variable is not synchronized and it seems that is has no effect.

4
  • 2
    ...why it works... It would be helpful if you said what "works" means. That's not always obvious, especially for a program like yours that does not produce any output. I'm guessing that "works" means that the program stops reasonably soon after one second has elapsed. Commented Sep 2, 2016 at 20:31
  • You need synchronization (or volatile) to guarantee the behavior you want, but if you don't have it, you might still get it if you're lucky (small programs like this make it easier to be lucky). In other words, "you're not guaranteed X" is different from "you're guaranteed not X." Commented Sep 2, 2016 at 20:33
  • If I try to do the same thing to the stopRequested()... If you try to do what same thing? What is the thing that you did? What did you do it to? Are you saying that if you add synchronized to the declaration of stopRequested()? Commented Sep 2, 2016 at 20:33
  • "with the same thing" i referred to throw away synchronized in the second method Commented Sep 2, 2016 at 20:36

4 Answers 4

2

synchronized is reentrant, the same thread that acquired the lock of synchronized block is guaranteed that it'll keep it on the next try to acquired if it still own the lock, but this doesn't have to do with the fact that the change over stopRequested is made outside a synchronized block and still the code works, your code still may have a race condition under it actual circumstances.

Let say that at execution N the thread must terminate due on condition meet by stopRequested() and at the same time the requestStop() is called, it's not guaranteed that the thread terminate at N+1 because the variable stopRequested is not protected by exclusive lock in both accessor methods, nor the variable has volatile modifier. That means that the sense of correctness you have about the code, is partially wrong, because of race conditions.

Sign up to request clarification or add additional context in comments.

3 Comments

Under the light of thread-safety is not completely correct. it may have condition corruptions, It like @yshavit said. small programs like this make it easier to be lucky it'll be possible run for a long time not showing sign of error but someday it will appear.
Usually people say "race condition" when they mean that the correct output of the program depends on things happening in a certain order when there is nothing in the program that guarantees them happening in that order. In this program, the only "output" is, eventually the program halts.
Not like that but the affected variable i may have the not expected value at the end of the while-loop.
1

The Java Lanaguage Specification does not say if or when this program will terminate.

You can only be sure it will terminate after approximately one second if both methods, requestStop() and stopRequested(), are synchronized.

If either one is not synchronized, or if neither of them is synchronized, then the program could terminate after one second, or after five seconds, or never. It could behave differently in different Java Run-time Environments. It could behave differently on different hardware. It could behave differently on different days of the week.

Without both methods being synchronized, its behavior is undefined.

Comments

1

The synchronized blocks have additional semantics in Java. They not only provide exclusive execution of blocks of code, but also emit so called memory barriers that guarantee visibility of the results of all the operations between threads.

So, when you call a synchronized stopRequested() method, you also make all the changes visible to the current thread. If you remove synchronized from this method, you also remove the barrier and JVM doesn't guarantee you that the flag you set in the main thread is visible in the background thread. That's why you have problems without synchronized.

Comments

1

There is a quote by Dion Almaer referenced in the preface of Java Concurrency in Practice:

Dion Almaer, former editor of TheServerSide, recently blogged (after a painful debugging session that ultimately revealed a threading bug) that most Java programs are so rife with concurrency bugs that they work only "by accident".

This is one of those. The Java language spec does not make any promise that the updated flag will be visible. If you don't follow the rules then you're at the mercy of the JVM implementation with respect to whether your thread ever sees the new value of your flag.

Some JVM implementations are more forgiving than others, some are designed to be more aggressive about how they cache things. If it works for you locally that does not mean it will work in production.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.