Home > Back-end >  Java Concurrency (Multithreading) - parallel() outcomes differ with tryLock()
Java Concurrency (Multithreading) - parallel() outcomes differ with tryLock()

Time:09-04

In the below code total is always 45, but total1 is unpredictable. I feel total should be unpredictable too as threads are not depending whether lock is acquired by tryLock() or not. Please can anybody explain what is the difference in calculation of total and total1.

import java.util.concurrent.locks.*;
import java.util.concurrent.atomic.*;
import java.util.stream.*;

public class HelloWorld{
               
   private Lock vault = new ReentrantLock();
   private int total = 0;
   private int total1 = 0;

   public void deposit(int value) {
       try {
           vault.tryLock();
           total  = value;
       } 
       finally {
           vault.unlock();
       }
   }
                      
   public void add(int val) {
       total1  = val;
   }

   public static void main(String[] unused) {
       HelloWorld bank = new HelloWorld();

       IntStream.range(1, 10)
                .parallel()
                .forEach(s -> bank.deposit(s));

       System.out.println(bank.total);  //   45
                            
       HelloWorld bank1 = new HelloWorld();
       AtomicLong value1 = new AtomicLong(0);
       final long[] value2 = {0};
       IntStream.iterate(1, i -> 1).limit(100)
                .parallel()
                .forEach(i -> value1.incrementAndGet());
       IntStream.iterate(1, i -> 1).limit(100)
                .parallel()
                .forEach(i ->   value2[0]);   
       IntStream.iterate(1, i -> 1).limit(100)
                .parallel()
                .forEach(i -> bank1.add(i));
       System.out.println(value1 " " value2[0] " "  bank1.total1); // 100 94(Unpredictable) 96 (Unpredictable)

   }
}

CodePudding user response:

I feel total should be unpredictable too as threads are not depending whether lock is acquired by tryLock() or not.

I think you are right... Sort of.

Your program seems to allow different threads to access total with no synchronization (i.e., when vault.tryLock() happens to fail), but just because it is allowed to happen, that's not a guarantee that it actually will happen.

Testing for concurrency-related bugs sometimes works, and sometimes doesn't work. The Java language spec and the javadoc for the standard Java library guarantee certain behaviors if your program obeys certain rules, but they do not guarantee that your program will behave "wrongly" if it breaks the rules. They allow it, but they don't guarantee it.

CodePudding user response:

To make things confusing total and total1 aren't even calculating the same thing:

  • total is trying to compute 1 2 3 4 5 6 7 8 9
  • total1 is trying to compute 1 1 1 1 1 ...

If we just consider the threading though:

  • total calls the deposit method which is guarded by the lock.
  • total1 calls the add method which is not guarded.

Therefore total is predictable because the lock means only one thread at a time can do the add operation, but total1 is unpredictable because many threads could be doing each add operation at the same time.

  • Related