• 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
  • Ron McLeod
  • Paul Clapham
  • Devaka Cooray
  • Tim Cooke
Sheriffs:
  • Rob Spoor
  • Liutauras Vilda
  • paul wheaton
Saloon Keepers:
  • Tim Holloway
  • Tim Moores
  • Mikalai Zaikin
  • Carey Brown
  • Piet Souris
Bartenders:
  • Stephan van Hulst

Output even more unexpected than I was expecting!

 
Greenhorn
Posts: 21
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I've been experimenting with threads, and wrote the following two classes to test my understanding:




So, I was expecting output similar to:
Thread t1 i=0 p=0
Thread t1 i=1 p=1
Thread t3 i=0 p=2
Thread t2 i=0 p=3
Thread t1 i=2 p=4
Thread t3 i=1 p=5
Thread t2 i=1 p=6

My reasoning was:
  • I would expect the threads to execute in unpredictable order, so the output ought to be a random mix from the threads (i.e. anything from one after another to total mish-mash)
  • As i is a local variable, I would expect to see it increase by 1 each time a line was output from a thread. So all thread 1 output would have i incrementing in sequence, all thread 2 output would have it increments in sequence, etc.
  • As p is a class variable, and therefore shared between the threads, and incremented by all of them, I would expect to see p increase from 1 on the first line of output, to 2 on the second, 3 on the third, etc, regardless of the order in which the threads are executed.



  • Obviously I was wrong or I wouldn't be posting this. A sample of the actual output follows:
    Thread t2 i=0 p=0
    Thread t2 i=1 p=3
    Thread t2 i=2 p=4
    Thread t2 i=3 p=5
    Thread t2 i=4 p=6
    Thread t2 i=5 p=7
    Thread t2 i=6 p=8
    Thread t2 i=7 p=9
    Thread t2 i=8 p=10
    Thread t2 i=9 p=11
    Thread t2 i=10 p=12
    Thread t3 i=0 p=1
    Thread t3 i=1 p=13
    Thread t3 i=2 p=14
    Thread t3 i=3 p=15
    Thread t3 i=4 p=16
    Thread t3 i=5 p=17
    Thread t3 i=6 p=18
    Thread t3 i=7 p=19
    Thread t3 i=8 p=20
    Thread t3 i=9 p=21
    Thread t3 i=10 p=22
    Thread t1 i=0 p=2
    Thread t1 i=1 p=23
    Thread t1 i=2 p=24
    Thread t1 i=3 p=25
    Thread t1 i=4 p=26
    Thread t1 i=5 p=27
    Thread t1 i=6 p=28
    Thread t1 i=7 p=29
    Thread t1 i=8 p=30
    Thread t1 i=9 p=31
    Thread t1 i=10 p=32

    I'm confused. Can anyone help clear up what is going on?
     
    author
    Posts: 23956
    142
    jQuery Eclipse IDE Firefox Browser VI Editor C++ Chrome Java Linux Windows
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    output ought to be a random mix from the threads (i.e. anything from one after another to total mish-mash)
    I would expect the threads to execute in unpredictable order, so the As i is a local variable, I would expect to see it increase by 1 each time a line was output from a thread. So all thread 1 output would have i incrementing in sequence, all thread 2 output would have it increments in sequence, etc.



    Your program is pretty short, meaning the loop is pretty small, so don't be surprise if it looks likes the threads are doing multiple interations per timeslice. Remember that printing is done to buffers then eventually flushed so that won't slow it down. If you want a better mix, simulate actually doing stuff, like a complex calc, prior to printing.

    As p is a class variable, and therefore shared between the threads, and incremented by all of them, I would expect to see p increase from 1 on the first line of output, to 2 on the second, 3 on the third, etc, regardless of the order in which the threads are executed.



    First of all, p is not a class variable. This program works because all the threads are using the same object... but to answer your question... it is being incremented by all and hence are processed in order, but the printing is not in order. It is a very subtle distinction, but just think about it a bit.

    And finally, this class is not thread safe. The threads are all using the P variable without synchronization. You are actually lucky that you are not get weird values for p -- like two threads with the same p and such.

    Hope this helps,
    Henry
     
    Ranch Hand
    Posts: 1170
    Hibernate Eclipse IDE Ubuntu
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Ahh Henry, for shame

    You said p was not a class variable, then you went on to call the program unsafe due to p.

    'p' is what we call a member variable. Its a member of the class. I am not entirely sure i remeber the proper usage of the term 'class variable' so I will leave that alone.

    The point is each instance of the class gets its own copy of member variables. If you wanted p shared between instances you should have made it static.



    now you will have succeeded in creating a thread unsafe program, happy?

    And for the questions
    1. computers are not truly random. The OS knows the order. The OS is going to choose which threads to run when, and it would be less efficient to run 1 thread for a microsecond, then switch to another thread. So its gonna stick with 1 thread for a while. If you had an actual dual processor computer then you would see more agressive switching by the OS. Try slapping some Thread.yield calls in there and see if you can have any more fun.

    2. sounds right.

    3. see above.


    Since your threads are all daemon threads your program waits on them all. But you should probably have a thread.join in your main method, and make your other threds non-daemon threads. Its a design choice in truth.
     
    author
    Posts: 14112
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by CL Gilbert:
    The point is each instance of the class gets its own copy of member variables. If you wanted p shared between instances you should have made it static.



    All the threads are using the same instance. Therefore it's not threadsafe the way it's written.
     
    Henry Wong
    author
    Posts: 23956
    142
    jQuery Eclipse IDE Firefox Browser VI Editor C++ Chrome Java Linux Windows
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Ahh Henry, for shame

    You said p was not a class variable, then you went on to call the program unsafe due to p.



    CL, cool similey, I couldn't tell during posting what that one actually did... although the part of me from Brooklyn thought it did something else...

    And as Ilja explained, I stand by what I said.

    Henry
    [ October 16, 2004: Message edited by: Henry Wong ]
     
    Mr. C Lamont Gilbert
    Ranch Hand
    Posts: 1170
    Hibernate Eclipse IDE Ubuntu
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    yes. I have to admit to never noticing that possibility. Been writing Java for years and that fact never occurred to me.

    I really don't know what I been thinking all these years. I gotta go double check some old code
     
    Simon Birch
    Greenhorn
    Posts: 21
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Thanks for all the comments. The program wasn't intended to be used in any way. It was simply a test to see if I understood thread behaviour.

    I was making an unfounded assumption though - I assumed that a thread could only be interrupted when a line of code had finished executing.

    Looking at the output, I'm thinking that the program executed thread 2 up to the point where it has incremented p, but before it has constructed the String to be output. Processing then switched to thread 3, which was swapped out at the same point - after p has incremented, but before the output String is constructed. We then swap to thread 1, stop processing at the same point and then switch back to thread 2, which picks up by constructing the output String and outputing it. Thread 2 runs until it hits the end of the loop. Processing then switches to thread 3, and so on - I'll stop there, you're probably bored.

    Because I was expecting a whole line of code to be executed, I was expecting different output.

    I know the code as it stands is not threadsafe - but that was deliberate so I could get a handle on how threads worked.

    Once again, many thanks for all your comments. Please correct me though if the above is incorrect.
     
    Ranch Hand
    Posts: 1646
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Simon Birch:
    I was making an unfounded assumption though - I assumed that a thread could only be interrupted when a line of code had finished executing.


    Not only can a thread be interrupted while executing a line consisting of expressions, but so can writing a value to a long or double variable! This is because those are 64-bit values while the JVM is 32-bit. Threading can get quite tricky.
     
    blacksmith
    Posts: 1332
    2
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Simon Birch:

    Looking at the output, I'm thinking that the program executed thread 2 up to the point where it has incremented p, but before it has constructed the String to be output. Processing then switched to thread 3, which was swapped out at the same point - after p has incremented, but before the output String is constructed. We then swap to thread 1, stop processing at the same point and then switch back to thread 2, which picks up by constructing the output String and outputing it. Thread 2 runs until it hits the end of the loop. Processing then switches to thread 3, and so on - I'll stop there, you're probably bored.

    Yes, that's basically what Henry said; the only difference is that he suspect the interruption happened during the call to System.out.println() rather than during the String constructor.

    As Henry noted, though, things can get much worse than that. While the Java language specification requires execution within a single thread to proceed "as if ordered", this is not true across threads: from the point of view of thread t2, it might look like things in thread t1 are proceeding out of order.

    You could very easily get output like:

    Thread t2 i=0 p=10
    Thread t2 i=1 p=11
    Thread t3 i=0 p=10
    Thread t3 i=1 p=11
    Thread t1 i=0 p=0
    Thread t1 i=1 p=1
    etc.

    Because it might look to t2 like t1 had completed before t2 got to execute, and it might look to t3 like t2 hadn't executed at all by the time t3 started printing. In fact, depending on how System.out.println() is actually implemented, the above could result from a simple optimization that stored the value of p in a register during the loop.

    There are even wierder things that can theoretically happen prior to Java 1.5 - roughly equivalent to p starting to print with, say, a value of 42 in your example.

    The bottom line is, always use proper synchronization if you are going to communicate values across threads.
     
    Mr. C Lamont Gilbert
    Ranch Hand
    Posts: 1170
    Hibernate Eclipse IDE Ubuntu
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    What is special about java 1.5? Is there a new specifications?
     
    Henry Wong
    author
    Posts: 23956
    142
    jQuery Eclipse IDE Firefox Browser VI Editor C++ Chrome Java Linux Windows
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Well... 1.5 added a ton of stuff to make thread coding easier. This includes synchronization classes, services (like pools and schedulers), and the atomic library (which for those people who like to program threads optimistically, finally enables the practice)

    But... while there were some JVM improvements, I don't think anything was added to get rid of race conditions automatically -- at least, that I know of.

    Henry
     
    Greenhorn
    Posts: 13
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    as for te claims that this is not thread safe, I have a question...

    are both ++p and p++ atomic operations? if so, i don't see how this is not thread safe.
     
    Greenhorn
    Posts: 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Simon,
    As pointed out earlier by someone else, p here is not defined as class variable. Secondly, if you define i as volatile, that will force each thread to refresh its local copy of i before it actually tries to modify i. So Try following code.

    public class Unstable implements Runnable {
    private int p = 0;
    private volatile int i = 0;

    public void run() {
    for(; i <= 10; i++) {
    System.out.println("Thread " + Thread.currentThread().getName() + " i=" + i + " p=" + p++);
    }
    }
    }
     
    Ranch Hand
    Posts: 995
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by scott p laplante:
    as for te claims that this is not thread safe, I have a question...

    are both ++p and p++ atomic operations? if so, i don't see how this is not thread safe.



    All three threads access the same instance of the object so making any assumption on the field value would be hazardous.
    I don't know what are you refering as atomic? (one JVM instruction?)

    ./pope
     
    Alexandru Popescu
    Ranch Hand
    Posts: 995
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Simon you must run the application for a longer time in order to allow the machine to schedule (interpose) the threads.

    ./pope
     
    Paddy spent all of his days in the O'Furniture back yard with this tiny ad:
    Smokeless wood heat with a rocket mass heater
    https://woodheat.net
    reply
      Bookmark Topic Watch Topic
    • New Topic