0

I'm currently learning multithreading and I've found something interesting that I can't explain. To the best of my knowledge if two Threads are accessing a static variable they can make their own copies into their cache. An update made by Thread1 to the static variable in its local cache wont reflect in the static variable for Thread2 cache.

For this reason my isFound static variable in Cracker.java should be static and volatile, but it doesnt matter, because all Threads immediately stop when this exit condition is set to true. Can someone explain this to me?

HashDecryptor.java

 public class HashDecryptor {    

        private List<Thread> threads = new ArrayList<>();
        // some other fields

        public HashDecryptor() {            
            createThreads();
        }

        private void createThreads() {
            long max = (long) (Math.pow(26, numberOfChars));
            int n = numberOfThreads;
            for (int i = 0; i < n; ++i) {
                if (i == 0) {
                    threads.add(new Thread(new Cracker(hashToDecrypt, (max * i / n), (max * (i + 1) / n))));
                } else {
                    threads.add(new Thread(new Cracker(hashToDecrypt, (max * i / n) + 1, (max * (i + 1) / n))));
                }
            }
        }

        public void startDecryting() {
            for (Thread t : threads) {
                t.start();
            }
        }

    }

Cracker.java

public class Cracker implements Runnable {

    // Some other fields

    private static boolean isFound;

    public Cracker(String hashToDecrypt, long start, long end) {
        this.hashToDecrypt = hashToDecrypt;
        this.start = start;
        this.end = end;
    }

    @Override
    public void run() {
        decrypt();
    }

    public void decrypt() {
        LocalTime startTime = LocalTime.now();
        long counter = start;
        while (!isFound && counter <= end) {
            if (match(counter)) {
                isFound = true;
                printData(generatePassword(counter), startTime);
            }
            counter++;
        }
    }   

}
Zsolt Ébel
  • 120
  • 1
  • 9
  • 1
    Possible duplicate of [Volatile Vs Static in java](https://stackoverflow.com/questions/2423622/volatile-vs-static-in-java) – Flown Jun 23 '17 at 08:24
  • 2
    Are you referring to `isFound`? If you are finding that it works without the `volatile`, that is fluke. When the code changes, and/or the planets realign, it may stop working. – Andy Turner Jun 23 '17 at 08:25
  • @Flown How does that explain why does my code work without volatile? – Zsolt Ébel Jun 23 '17 at 08:35
  • Your code does not work. You can verify it by inserting `System.out.println(isFound);` after the while loop. Run it multiple times, then you'll see some of them will be `false`. – Flown Jun 23 '17 at 08:41
  • @Flown You wanna argue about does it work or not? :) I tell you it works fine, and I did verify it with sysouts. That's the strange thing about this, and that's why I asked this question :) – Zsolt Ébel Jun 23 '17 at 08:46
  • 2
    @Flown OP says that the code stops "immediately" when `isFound` is set to true. I don't know exactly how this was determined. But the point is that is valid behaviour according to the JMM - there's nothing to stop threads flushing/updating their locally-cached values at any time; it's just not *guaranteed*. OP has drawn the conclusion that the code works because it has not been observed not working, which isn't a correct conclusion. – Andy Turner Jun 23 '17 at 08:47
  • @AndyTurner Thanks for your answers. It was just an experiment and I found this quite interesting. I did changed back to volatile and static in my code. – Zsolt Ébel Jun 23 '17 at 08:50
  • @AndyTurner Agreed. _does not work_ is not the right statement. It should be _does not work correctly_. Since `isFound` is not the only termination condition it cannot end up infinite loop in one or more of the threads. – Flown Jun 23 '17 at 08:54

2 Answers2

0

For this reason my isFound static variable in Cracker.java should be static and volatile, but it doesn't matter, because all Threads immediately stop when this exit condition is set to true. Can someone explain this to me?

There are a number of ways that you can get incidental synchronization that might account for this. First of all, your application may be contending for CPU resources with other applications running on the hardware and the application may get swapped out. Maybe you have more threads than you have CPUs. Both of these may cause flushing of dirty memory to core memory when the threads get swapped out.

Another likely scenario is that your threads are crossing other memory barriers such as calling other synchronized methods or accessing other volatile fields. For example, I wonder about this statement because some of the input/output streams have synchronized classes.

printData(generatePassword(counter), startTime);

You might try to remove the printing of the data to see if your application behavior changes.

I tell you it works fine, and I did verify it with sysouts. That's the strange thing about this, and that's why I asked this question :)

Perfect example. System.out is a PrintStream which is a synchronized class so calling println() there will cause your thread to cross both a read and write memory barrier that will update your static field. It's important to note that any memory barrier affects all of the cached memory. Crossing any read memory barriers forces all cached memory to be updated from central memory. Crossing any write memory barriers forces all local dirty memory to be written to central.

The problem is when you remove the System.out methods or when you application stops calling the synchronized class and then that static variable is not properly updated. So you can't rely on it but it does happen.

Gray
  • 115,027
  • 24
  • 293
  • 354
0

Static variables :Are used in the context of Object where update made by one object would reflect in all the other objects of the same class but not in the context of Thread where update of one thread to the static variable will reflect the changes immediately to all the threads (in their local cache). If two Threads(suppose t1 and t2) are accessing the same object and updating a variable which is declared as static then it means t1 and t2 can make their own local copy of the same object(including static variables) in their respective cache, so update made by t1 to the static variable in its local cache wont reflect in the static variable for t2 cache .

Volatile variable: If two Threads(suppose t1 and t2) are accessing the same object and updating a variable which is declared as volatile then it means t1 and t2 can make their own local cache of the Object except the variable which is declared as a volatile . So the volatile variable will have only one main copy which will be updated by different threads and update made by one thread to the volatile variable will immediately reflect to the other Thread.

gati sahu
  • 2,576
  • 2
  • 10
  • 16