3

Java MultiThreading skips loop and gives wrong result

package Threading;

class DemoThread extends Thread{   //Thread Class   
    static int count=0;   // variable incremented by both the threads

    public DemoThread(String name) {
        // TODO Auto-generated constructor stub
        super(name);
    }

    public void run() { 
        for(int i=0;i<100000;i++) {
            count++;
            System.out.println(Thread.currentThread()+"Count"+count);  // print thread operating on count variable
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }           
        }       
    }   
}


public class MyThreadClass {

    public static void main(String[] args) {
        // TODO Auto-generated method stub      
        DemoThread t1=new DemoThread("T1");
        DemoThread t2=new DemoThread("T2");
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();  //allowing both the threads to complee before main thread
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("Main Thread ends"+DemoThread.count);  //final value of count        
    }
}

The final value of count should be 199998 but it is not giving the desired result. Why the threads are missing the loops ???

Monasha
  • 711
  • 2
  • 16
  • 27
arif abbas
  • 341
  • 2
  • 6

3 Answers3

3

It happened because Thread T1 and T2 will update count at the same time (concurrency) like that:

Thread[T1,5,main]Count10
Thread[T2,5,main]Count10
Thread[T1,5,main]Count12
Thread[T2,5,main]Count12
Thread[T2,5,main]Count14
Thread[T1,5,main]Count14
Thread[T1,5,main]Count15
Thread[T2,5,main]Count16

You should use AtomicInteger

And update your code:

static int count=0; to static AtomicInteger count= new AtomicInteger();

count++; to count.incrementAndGet();

Viet
  • 3,349
  • 1
  • 16
  • 35
  • but why...at a time only 1 thread will get into runnable i.e. gets the CPU right ??? – arif abbas Nov 14 '16 at 09:42
  • 1
    No, you need learn more about runnable ,thread and parallel. I think http://www.vogella.com/tutorials/JavaConcurrency/article.html#what-is-concurrency is a good article – Viet Nov 14 '16 at 09:55
  • It really helped..I understand , it depends upon the CPU cores we can have concurrency as several threads might access a shared data simultaneously – arif abbas Nov 14 '16 at 15:02
1

You must use java.util.concurrent.atomic.AtomicInteger and not a shared static int variable.

Serg M Ten
  • 5,568
  • 4
  • 25
  • 48
0

Problem

In Java, multi threading introduces asynchronous behavior to your programs, you must enforce synchronicity when you need it.

Without synchronization, nothing stops a thread to access from calling a same method, on same object at the same time. This is known as Race Condition, because threads are racing each other to complete the method.

The output to your program:
enter image description here

The first line of the output printed 2!? This is because t1 wrote count's value and was preempted before it could print it. Note that for a thread to be preempted it need not go into sleep. OS does this neverthless.

If you notice the 1st line and 4th line you can see the inconsistency. This kind of inconsistency becomes unpredictable in huge programs.

Here are end results for running multiple times.

enter image description here

enter image description here

It should not be taken granted that always wrong results are produced. No, sometimes correct results are produced. It means that results will be unpredictable.


Misunderstanding on?

Thread skipped loop.!? No, thread didn't skip loop. Different threads accessed same value but before it could write it's own value other thread wrote the value and proceeded. As a result the next time it accessed the value, it picked up the wrong value.

This is known as Reader Writer Problem


Solution

In your program, t1 and t2 are accessing your count variable with different values. To prevent other threads from calling run() before other thread completes it we add a synchronized keyword before the method.

synchronized public void run(){}

The synchronized keyword guards the state from race conditions. Once, a thread enters the synchronized method, other threads are not allowed to use the method until the previous thread exits the method.

Here is the correct output due to synchronized keyword. Note: I used 200 as the end for loop.

enter image description here

enter image description here


Bonus

If there are proprietary methods you are using which take in shared data as input. You can use synchronized block

synchronized(objRef){
   //Method calling
}

objRef is the reference of the object being synchronized.


As recommended in comments
[Recommended Solution]

You should use AtomicInteger instead of native int. Use java.util.concurrent.atomic package.

Reference to java.util.concurrent.atomic

Instead of static int count = 0; use static AtomicInteger count = new AtomicInteger(0); and instead of count++; use count.incrementAndGet();

AtomicInteger is inherently synchronized.

Atomic Integer Reference Java Docs


Tarun Maganti
  • 3,076
  • 2
  • 35
  • 64
  • 2
    Verbose, but good explained. However, the conclusion should rather be using AtomicInteger (which is implemented exactly for OP's purpose) instead of shotgun synchronization. – SME_Dev Nov 14 '16 at 10:14
  • @SME_Dev I have added the AtomicInteger as recommended. – Tarun Maganti Nov 14 '16 at 10:28
  • @SME_Dev of course an even better solution would be for both Threads to have their own count and to add them together, eliminating all need for synchronization during the run – bowmore Nov 14 '16 at 12:18
  • @bowmore Well, the given example is arbitrary of course. In the OP's test case, _the cummulated count is the predicate to break the outer loop_. You before this sum is equal to the limit, the threads don't know whether they can terminate and "add the result". So your idea means that you sum up after you know the sum's value, right? – SME_Dev Nov 14 '16 at 13:39
  • @SME_Dev Yes, the example is arbitrary, I'm just trying to say that in some cases it is possible to eliminate the need for synchronization, which, if possible, is the ultimate solution. Whether or not it is perfectly applicable to the OP's example is not so relevant for what I intended to convey. – bowmore Nov 14 '16 at 15:18