CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 6 of 6
  1. #1
    Join Date
    Feb 2009
    Posts
    7

    Need help understanding results from running 2 threads

    Hi All,

    I have just dived into the world of threads and am having a little play. I'm written the following code but the results are not as I expect them to be, I hope someone can enlighten me on what is happening?!?:

    Code:
    public class ThreadTest
    {
        Thread thread1;
        Thread thread2;
        int counter = 0;
        boolean flag = true;
    
        public ThreadTest()
        {
            Runnable runnable1 = new Runnable()
            {
                public void run()
                {
                    while(flag)
                    {
                        System.out.println("Runnable1 is reading");
                        if(counter != 100)
                        {
                            System.out.println("Runnable1 is about to update the counter");
                            updateCounter();
                            System.out.println("Runnable1 has written " + counter);
                        }
                        else
                        {
                            flag = false;
                        }
                    }
                }
            };
            Runnable runnable2 = new Runnable()
            {
                public void run()
                {
                    while(flag)
                    {
                        System.out.println("Runnable2 is reading");
                        if(counter != 100)
                        {
                            System.out.println("Runnable2 is about to update the counter");
                            updateCounter();
                            System.out.println("Runnable2 has written " + counter);
                        }
                        else
                        {
                            flag = false;
                        }
                    }
                }
            };
            thread1 = new Thread(runnable1);
            thread1.setName("Thread 1");
            thread2 = new Thread(runnable2);
            thread2.setName("Thread 2");
        }
    
        synchronized public void updateCounter()
        {
            counter++;
        }
    
        public void go()
        {
            thread1.start();
            thread2.start();
        }
    
        public static void main(String[] args)
        {
            ThreadTest myTest = new ThreadTest();
            myTest.go();
        }
    }
    Now, during a certain run of the above code, I received the following results:

    Runnable1 is reading
    Runnable2 is reading
    Runnable1 is about to update the counter
    Runnable2 is about to update the counter
    Runnable1 has written 2
    Runnable1 is reading
    Runnable1 is about to update the counter
    Runnable1 has written 3
    Runnable1 is reading
    Runnable1 is about to update the counter
    Runnable1 has written 4
    Runnable1 is reading
    Runnable1 is about to update the counter
    Runnable1 has written 5
    Runnable1 is reading
    Runnable1 is about to update the counter
    Runnable1 has written 6
    Runnable1 is reading
    Runnable1 is about to update the counter
    Runnable1 has written 7
    Runnable1 is reading
    Runnable1 is about to update the counter
    Runnable2 has written 2
    Runnable2 is reading
    Runnable2 is about to update the counter
    Runnable2 has written 9
    Runnable2 is reading

    My question is, why does Runnable2 change the counter value to '2' when it calls the updateCounter() method since Runnable1 has been running and has already changed the counter value to '7' or higher. I mean, the method updateCounter() is just doing counter++. I.e. counter = counter + 1. Therefore a new read of counter is carried out and at this stage, counter should be identified as '7' or higher. The changes made should have been tracked theoretically unless I'm missing sosmething obvious?

    Any explanation would be appreciated. Feel free to run the code and see similar results firsthand.
    Thanks

  2. #2
    Join Date
    Feb 2008
    Posts
    966

    Re: Need help understanding results from running 2 threads

    The reason that thread 2 updates the counter to 2 is because it has its own instance of the class level variables. You create two new threads and start each one independently. They are operating as ThreadTest objects. Creating two threads of that class will create two objects.

    Do this to test things out: first, print out this.getName() and print it out.

    Next test to run is set the counter variable as static and see what happens. Let us know the results

  3. #3
    Join Date
    Nov 2009
    Posts
    17

    Re: Need help understanding results from running 2 threads

    They have a shared instance of the counter variable.

    The reason you are seeing results that you aren't expecting is because you aren't synchronizing your print statements as well.

    Try the following code (This has other problems, but the output will look a lot more like what you expected)..... All I did was move the print statements into the synchronized updateCounter

    Code:
    public class ThreadTest
    {
        Thread thread1;
        Thread thread2;
        int counter = 0;
        boolean flag = true;
    
        public ThreadTest()
        {
            Runnable runnable1 = new Runnable()
            {
                public void run()
                {
                	System.out.println(this.getClass().getName());
                    while(flag)
                    {
                        System.out.println("Runnable1 is reading");
                        if(counter != 100)
                        {
                            updateCounter("Runnable1");
                        }
                        else
                        {
                            flag = false;
                        }
                    }
                }
            };
            Runnable runnable2 = new Runnable()
            {
                public void run()
                {
                	System.out.println(this.getClass().getName());
                    while(flag)
                    {
                        System.out.println("Runnable2 is reading");
                        if(counter != 100)
                        {
                            updateCounter("Runnable2");
                         
                        }
                        else
                        {
                            flag = false;
                        }
                    }
                }
            };
            thread1 = new Thread(runnable1);
            thread1.setName("Thread 1");
            thread2 = new Thread(runnable2);
            thread2.setName("Thread 2");
        }
    
        public synchronized void updateCounter(String runnable)
        {
        	System.out.println(runnable + " is about to update the counter");
            counter++;
            System.out.println(runnable + " has written " + counter);
        }
    
        public void go()
        {
            thread1.start();
            thread2.start();
        }
    
        public static void main(String[] args)
        {
            ThreadTest myTest = new ThreadTest();
            myTest.go();
        }
    }

  4. #4
    Join Date
    Feb 2009
    Posts
    7

    Re: Need help understanding results from running 2 threads

    Quote Originally Posted by ProgramThis View Post
    The reason that thread 2 updates the counter to 2 is because it has its own instance of the class level variables. You create two new threads and start each one independently. They are operating as ThreadTest objects. Creating two threads of that class will create two objects.

    Do this to test things out: first, print out this.getName() and print it out.

    Next test to run is set the counter variable as static and see what happens. Let us know the results
    Hi ProgramThis,

    Thanks for the quick response. I appreciate it although I do not believe your explanation to be correct. I believe both innner class instances when created are tied to the same outer class instance so both have access to the same outer class instance variables. - They do not each get a seperate copy and I believe that is the main benefit of using inner classes? - I have only instantiated one ThreadTest object.
    I believe I have the answer to the unusual result which was provided on another forum:

    "The problem here is in the reporting. You are synchronizing the counter++ part, but are not synchronizing anything else. This means that the reporting may be out of sync.

    The key to remember here is that this line of code is actually multiple steps:

    Code:
       1. System.out.println("Runnable2 has written " + counter);
    It can turn into code that reads like this (not actual byte code - just an example):

    Code:
       1. get "Runnable2 has written " (from String pool)  
       2. get counter (from central store into thread store)  
       3. concat "Runnable2 has written " and counter  
       4. send concatenated String to output  
       5. flush output
    The instruction can be interrupted at any point in there to allow a different thread to run. What looks like it may be happening is that Runnable2 gets through the 'get counter' part (and maybe anywhere before the flush command) first, but the context gets switched to Runnable1 before the flush occurs. So you see Runnable1's output first. Runnable1 makes several changes then the thread context switches back toe Runnable2, which already has a value for counter which is stale, it flushes the output and you get what looks like an out of sequence value, but which is probably just a stale report.

    If you need to make sure the report is up to date with the counter (and prevent this sort of stale data from leaking out) then you need to put the report (the System.out.println) in the same synchronized block as the code which does the data update. "

    Many Thanks

  5. #5
    Join Date
    Nov 2009
    Posts
    17

    Re: Need help understanding results from running 2 threads

    I think this is a better solution (less code duplication).... In this case ProgramThis would have been correct that they each would have their own counter, so it is a static variable in this case.
    Code:
    public class ThreadTest implements Runnable
    {
        public static int counter = 0;
        boolean flag = true;
        public String name;
        public static Object lock = new Object();
        
        public void run()
        {
        	System.out.println(this.getClass().getName());
            while(counter < 100)
            {
                System.out.println(name + " is reading");
                if(counter < 100)
                {
                    updateCounter(name);
                }
                else
                {
                    flag = false;
                }
            }
        }
        
        public ThreadTest(String name)
        {
        	this.name = name;
        }
    
        public void updateCounter(String runnable)
        {
        	synchronized (lock) {
        		System.out.println(runnable + " is about to update the counter");
        		counter++;
        		System.out.println(runnable + " has written " + counter);
        	}
        }
        public static void main(String[] args)
        {
            (new Thread(new ThreadTest("Runnable1"))).start();
            (new Thread(new ThreadTest("Runnable2"))).start();
        }
    }
    Last edited by DavidFongs; December 2nd, 2010 at 04:53 PM.

  6. #6
    Join Date
    Feb 2008
    Posts
    966

    Re: Need help understanding results from running 2 threads

    You are absolutely right, I apologize for making a hasty reply without looking closely at your code.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured