简体   繁体   中英

Java Thread Synchronized methods

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.

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.

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.

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.

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM