• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Problem in Threading

 
Ranch Hand
Posts: 37
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Question from Niko's blog...

I am not able to understand the above program, I am thinking the output should be 2000, but that is not the case.
There is only one Account object on which the Client would synchronize. Once the setNumber() method is called, that thread will own the lock on account object and any other thread would not be able to execute that method(or getNumber()) method. But somehow the output is not as expected by me.
Even making all the members of Account static does not produce 2000 output.
One way to get 2000 as output is place the statement one.join(); before two.start();, but that is very obvious...
Can anyone please explain what is going on?
 
Ranch Hand
Posts: 2066
IntelliJ IDE Clojure Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
synchronize the account object in your run() method rather than synchronizing it in the setter/getter methods.
 
Ranch Hand
Posts: 276
Netbeans IDE Chrome Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Divyeshh Patel wrote:
There is only one Account object on which the Client would synchronize. Once the setNumber() method is called, that thread will own the lock on account object and any other thread would not be able to execute that method(or getNumber()) method. But somehow the output is not as expected by me.
Can anyone please explain what is going on?


This is what happens...
  • Thread1 comes in first(lets assume) inside the loop, gets the lock, calls getNumber() , releases the lock & immediately gets the lock again and calls setNumber() (because getNumber() is called in the argument.JVM after solving the argument will directly call the method).
  • This may continue for some time. We can determine it. Depends on the OS. Lets say i=55 has completed, the set number is 55 now.
  • When the context is switched on to Thread2, it enters its own loop with i=1. It now gets the lock, calls getNumber() (which is now going to return 55 as the Account object is common to both the threads), calls setNumber().
  • This may again go on for some time. Lets say when thread2's i=25, number in Account is 70.
  • Steps 1 to 4 goes on again...

  • So, since you cant determine what thread runs for what time, you always will get an output above 1000(obvious), but expect any number!
    If you do something which you are not really sure about, THREADs are going to surprise you!

    Divyeshh Patel wrote:I am not able to understand the above program, I am thinking the output should be 2000, but that is not the case.
    Even making all the members of Account static does not produce 2000 output.


    If you want a 2000,then it means you want to run the threads one after another,right? You really want to do that?
    In that case, as Abi said you must synchronize on your account Object in your run() method/add synchronized your run() method itself - both are going to run one after another!
     
    Divyeshh Patel
    Ranch Hand
    Posts: 37
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Thanks for the answer Vinoth(and Abhimaran).
    It is not my intention to get 2000 as the answer, I am just trying to figure out how the code is working.
    @Vinoth

    you always will get an output above 1000(obvious),


    This is not always the case, many a times the output is less than 1000.
    Another thing, when getNumber() is called, the executing thread already owns lock on the account object(by the call to setNumber()), so no other thread can call either of the methods. This is what I am thinking.
    Don't know what exactly is going on...
     
    Vinoth Kumar Kannan
    Ranch Hand
    Posts: 276
    Netbeans IDE Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Divyeshh Patel wrote:
    Another thing, when getNumber() is called, the executing thread already owns lock on the account object(by the call to setNumber()), so no other thread can call either of the methods. This is what I am thinking.
    Don't know what exactly is going on...


    As I already said, the executing thread will first call getNumber() even before setNumber(). Only after the arguments get resolved, does the method gets called.
    The thread calls getNumber(), own a lock, complete getNumber(), release the lock, call setNumber(), own a lock, complete setNumber(), release the lock - The actual flow.

    Divyeshh Patel wrote:This is not always the case, many a times the output is less than 1000.


    Yeah, after running the code for about 15 or 20 times, I got 918,953... Wondering why this is happening...
     
    Bartender
    Posts: 543
    4
    Netbeans IDE Redhat Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    You have thread one and thread 2 calling get and set continuously.

    Now, you don't know what thread will access what method, and when. It may as well be below thousand. I'll show you why:

    So what happens many times is:

    -number = 5
    -thread 1 gets number (5)
    -thread 2 gets number (5) //say, i == 6
    -thread 2 sets number (6)
    -thread 2 gets number (6) // i == 7
    -thread 2 sets number (7)
    -thread 2 gets number (7) // i == 8
    -thread 2 sets number (8)
    -thread 1 sets number (6)
    -thread 1 gets number (6)

    -thread 2 gets number (6)
    -thread 2 sets number (7) // i == 9
    -thread 2 gets number (7)
    -thread 2 sets number (8) // i == 10
    -thread 2 gets number (8)
    -thread 2 sets number (9) // i == 11
    -thread 2 gets number (9)
    -thread 2 sets number (10) // i == 12
    -thread 1 sets number (7)


    So what happens is, if thread 1 runs its getter, and then thread 2 runs 100 times in a row, and THEN thread 1 sets its value, number will be set to a 100 less than thread 2's index points. Then if thread 2 runs its getter at a 100 less, and thread 1 runs 100 times in a row, and THEN thread 2 sets its value, number will be set to 100 less than thread 1's index value points... So the outcome of both indexes could as well be less than 100, if the cards fall just right.

    What you know is:

    - thread 1 and thread 2 cannot both access the getter at the same time
    - thread 1 and thread 2 cannot both access the setter at the same time

    What happens between the getter is run and the setter is run? You don't know! It's up to the thread scheduler, which is usually platform-dependent!
     
    Rancher
    Posts: 1337
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Synchronizing the run method is not strictly necessary. In fact, you don't want to do that as it effectively destroys concurrency, making one thread do all its work before the other even starts.

    The code that needs to be synchronized is "account.setNumber(account.getNumber() + 1)" in its entirety. Once you do that, the getNumber and setNumber methods don't need to be synchronized. Note that it needs to be synchronized on the same object for both threads, so something like "synchronized (this) { ... }" is not going to work, but, for example, "synchronized (Client.class) { ... }" is fine.

    I leave it as exercise to figure out how you can make do without explicit synchronization by using the java.util.concurrent.atomic.AtomicInteger class :-)
     
    Abimaran Kugathasan
    Ranch Hand
    Posts: 2066
    IntelliJ IDE Clojure Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Lester Burnham wrote:
    The code that needs to be synchronized is "account.setNumber(account.getNumber() + 1)" in its entirety. Once you do that, the getNumber and setNumber methods don't need to be synchronized.


    This will give you the same effect as the original post of this thread! Did you try?
     
    Vinoth Kumar Kannan
    Ranch Hand
    Posts: 276
    Netbeans IDE Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Dieter Quickfend wrote:
    -number = 5
    -thread 1 gets number (5)
    -thread 2 gets number (5) //say, i == 6
    -thread 2 sets number (6)
    -thread 2 gets number (6) // i == 7
    -thread 2 sets number (7)
    -thread 2 gets number (7) // i == 8
    -thread 2 sets number (8)
    -thread 1 sets number (6)
    -thread 1 gets number (6)

    -thread 2 gets number (6)
    -thread 2 sets number (7) // i == 9
    -thread 2 gets number (7)
    -thread 2 sets number (8) // i == 10
    -thread 2 gets number (8)
    -thread 2 sets number (9) // i == 11
    -thread 2 gets number (9)
    -thread 2 sets number (10) // i == 12
    -thread 1 sets number (7)


    Ah....Dieter..thanks for that explanation.
    I was assuming that nothing could come between get and set methods..meaning, I just thought once the argument is solved, set method will be called immediately without allowing any other thread inbetween & i was wrong. Now got it completely!
     
    Lester Burnham
    Rancher
    Posts: 1337
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Abimaran Kugathasan wrote:This will give you the same effect as the original post of this thread!


    It does not; it returns 2000 every time. What are you talking about?
     
    Ranch Hand
    Posts: 623
    1
    IntelliJ IDE Java Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Abimaran Kugathasan wrote:

    Lester Burnham wrote:
    The code that needs to be synchronized is "account.setNumber(account.getNumber() + 1)" in its entirety. Once you do that, the getNumber and setNumber methods don't need to be synchronized.


    This will give you the same effect as the original post of this thread! Did you try?



    Remember to synchronize on 'account' instead of 'this' (== current thread).
     
    Divyeshh Patel
    Ranch Hand
    Posts: 37
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Thanks everyone for the replies.
    I think I am clear with this program now.
     
    Don't get me started about those stupid light bulbs.
    reply
      Bookmark Topic Watch Topic
    • New Topic