Results 1 to 10 of 10
  1. #1
    Anarch is offline Member
    Join Date
    Apr 2015
    Posts
    7
    Rep Power
    0

    Default Threads share static variable but behave differently with respect to it

    Here is my code. Obviously this doesn't do a lot but that's only because I abstracted out the problem so that you guys didn't have so many lines to decipher.

    Java Code:
    import java.util.Scanner;
    
    class threadOne extends threadTwo {
    	
    	public static void main(String[] args) {
    		
    		threadTwo threadTwoObj = new threadTwo();
    		threadTwoObj.start();
    		
    		while (!userInput.equals("exit")) {
    			Scanner scannerObj = new Scanner(System.in);
    			userInput = scannerObj.nextLine();
    		}
    		
    	}
    	
    }
    Java Code:
    class threadTwo implements Runnable {
    
    	private Thread threadObj;
    	public static String userInput = "default";
    
    	public void start() {
    		threadObj = new Thread (this, "Thread Two");
    		threadObj.start();
    	}
    	
    	public void run() {
    		while (!userInput.equals("exit")) {}
    	}
    }
    What its supposed to do: When the user returns "exit" in the console it is supposed to break out of both while loops in both threads.
    What it actually does: breaks out of the while loop in threadOne and not in threadTwo.

    In case you are wondering the idea behind this, basically the idea is to have a thread running doing computation and another thread able to query it for updates or interact to make changes to the flow. This will be useful, among other ways, for the sorts of problems where finding a solution is easy but where a better solution can always be found with more time. So for example finding directions on a map. Its easy to find a solution, but if you search longer you can find a faster route, if you search longer still than faster still.

  2. #2
    pbrockway2 is offline Moderator
    Join Date
    Feb 2009
    Location
    New Zealand
    Posts
    4,717
    Rep Power
    17

    Default Re: Threads share static variable but behave differently with respect to it

    If you have multiple threads accessing the same shared memory then each thread should ensure that it has exclusive use of the memory (variable) by obtaining a lock or by making sure that its access is atomic (== happens all at once with no side effects visible until it has finished).

    In this case you could make the access to the static variable atomic by declaring it as

    Java Code:
    public static volatile String userInput = "default";
    There is a Synchronization lesson in Oracle's Tutorial which discusses all this. It is part of the Concurrency section all of which is valuable.

    ---

    Have a read, also, of this SO thread which discusses precisely your problem, and note why "busy wait" loops doing a volatile read are frowned upon. The suggestion of using an explicitly created lock object might be a better way to go.

  3. #3
    jim829 is offline Senior Member
    Join Date
    Jan 2013
    Location
    Northern Virginia, United States
    Posts
    6,226
    Rep Power
    13

    Default Re: Threads share static variable but behave differently with respect to it

    Well, it works for me. Try putting print statements after each while loop. Do something like the following:

    Java Code:
    System.out.println(Thread.currentThread.getName() + " - done!");
    And your idea for using threads to continue processing for better solutions in any scenario is basic to thread programming.
    Also, by convention class names should start with uppercase characters. For more on Java conventions, check the link in my signature.

    Regards,
    Jim
    The JavaTM Tutorials | SSCCE | Java Naming Conventions
    Poor planning on your part does not constitute an emergency on my part

  4. #4
    Anarch is offline Member
    Join Date
    Apr 2015
    Posts
    7
    Rep Power
    0

    Default Re: Threads share static variable but behave differently with respect to it

    Thanks wizards. Adding that one little word volatile to my code fixed it like magic.

    I am going to read those resources tomorrow and if the answer to this question is in there than feel free to ignore the question. But I cant help but still a little curious why it had that particular behavior. Based on your description of the problem pb, it seems like the sort of thing that would work most of the time or at least some of the time but then every once in a while blow up spectacularly. Is it safe to assume that this particular behavior is a result of some sort of safety mechanism(s) built either into the compiler or the jvm?

    Sorry for not just letting it rest now that i have my answer. I'm kind of a geek for trying to understand how everything is working under the hood.

  5. #5
    pbrockway2 is offline Moderator
    Join Date
    Feb 2009
    Location
    New Zealand
    Posts
    4,717
    Rep Power
    17

    Default Re: Threads share static variable but behave differently with respect to it

    To be honest I was merely responding with the knee jerk reaction "if multiple threads access the same shared memory their access must be synchronised."

    Often weird things can happen when one thread is writing a double value for example and another is reading it. The reader might get to see the newly written first half of the double while still reading the older second half.

    Here it's different. It looks like the second while loop is being rather aggressively optimised because it only makes reference to a non volatile variable. It is by making the variable volatile that you guarantee that writes to it (in the other thread) happen before - ie are visible to - every subsequent read. (See for example What does synchronization do?) in the jsr-133 faq.

  6. #6
    Anarch is offline Member
    Join Date
    Apr 2015
    Posts
    7
    Rep Power
    0

    Default Re: Threads share static variable but behave differently with respect to it

    thanks so much for all of the help and follow up info. drop a bitcoin address in here if you would like a tip.
    Last edited by Anarch; 04-26-2015 at 06:17 AM.

  7. #7
    jim829 is offline Senior Member
    Join Date
    Jan 2013
    Location
    Northern Virginia, United States
    Posts
    6,226
    Rep Power
    13

    Default Re: Threads share static variable but behave differently with respect to it

    Quite frankly I don't see how declaring the String volatile solved the ops problem. It doesn't really make the String atomic in a literal sense because the String is being updated via user input which has many steps involved. I would also think that the threads are looping so quickly and that typing in a word is relatively slow that both threads should have seen the change. Like I said in my post, for me it behaved as the OP wanted without the volatile declaration. Of course, I did put the classes in the same file and I had to prefix the class name when referencing userInput (and there are a multitude of other potential differences too). I would expect that if the loops were running slower than the user was typing then one of four alternatives could have happened. One or the other thread quits. Both quit or neither quit.

    Regards,
    Jim
    The JavaTM Tutorials | SSCCE | Java Naming Conventions
    Poor planning on your part does not constitute an emergency on my part

  8. #8
    Anarch is offline Member
    Join Date
    Apr 2015
    Posts
    7
    Rep Power
    0

    Default Re: Threads share static variable but behave differently with respect to it

    For me they are in separate files in the same folder (not using a ide, just notepad++ and the command line if thats relevant). Also it may be worth noting that when i put even a small pause in the form of thread.sleep() in threadTwo it functions properly without declaring volatile.

  9. #9
    pbrockway2 is offline Moderator
    Join Date
    Feb 2009
    Location
    New Zealand
    Posts
    4,717
    Rep Power
    17

    Default Re: Threads share static variable but behave differently with respect to it

    For me the classes were exactly as posted in a single file.

    Java Code:
    pbrockway@pbrockway-OptiPlex-980:~/Desktop$ javac threadOne.java 
    Picked up JAVA_TOOL_OPTIONS: -javaagent:/usr/share/java/jayatanaag.jar 
    pbrockway@pbrockway-OptiPlex-980:~/Desktop$ java threadOne
    Picked up JAVA_TOOL_OPTIONS: -javaagent:/usr/share/java/jayatanaag.jar 
    Asd
    Dsa
    exit
    exit!!1!
    exit
    ^Cpbrockway@pbrockway-OptiPlex-980:~/Desktop$
    @Jim: why did you have to prefix userInput? It's static and declared in the super class.

    I can't find anything on line about how loops are optimised, but the comments in the jsr-133 faq I linked to above suggest that a compiler might well take while(!userInput.equals("exit")) {} and turn it in to if(!userInput.equals("exit")) {while(true) {}} since userInput is not volatile.

    I agree that both threads "should" see the change (where should == we would expect them to, or we intend them to). But what, in the code (besides volatile or aquiring/releasing a lock) ensures that they do?

    The relevant few paragraphs of the faq are:

    Synchronization has several aspects. The most well-understood is mutual exclusion -- only one thread can hold a monitor at once, so synchronizing on a monitor means that once one thread enters a synchronized block protected by a monitor, no other thread can enter a block protected by that monitor until the first thread exits the synchronized block.

    But there is more to synchronization than mutual exclusion. Synchronization ensures that memory writes by a thread before or during a synchronized block are made visible in a predictable manner to other threads which synchronize on the same monitor. After we exit a synchronized block, we release the monitor, which has the effect of flushing the cache to main memory, so that writes made by this thread can be visible to other threads. Before we can enter a synchronized block, we acquire the monitor, which has the effect of invalidating the local processor cache so that variables will be reloaded from main memory. We will then be able to see all of the writes made visible by the previous release.

    Discussing this in terms of caches, it may sound as if these issues only affect multiprocessor machines. However, the reordering effects can be easily seen on a single processor. It is not possible, for example, for the compiler to move your code before an acquire or after a release. When we say that acquires and releases act on caches, we are using shorthand for a number of possible effects.

  10. #10
    jim829 is offline Senior Member
    Join Date
    Jan 2013
    Location
    Northern Virginia, United States
    Posts
    6,226
    Rep Power
    13

    Default Re: Threads share static variable but behave differently with respect to it

    First, I made a mistake (not certain how it happened). When I pasted the code in my IDE for some reason threadOne did not extend threadtwo. So I reran the program and it still worked without the volatile. I did not mean to imply that using volatile optimized the loops. Your example of hoisting is what I was talking about. Consider a method working on an instance field. I believe the rule is the compiler may change the order of any single set of instructions as long as the expected state exists by the time the method is finished. To prevent that from happening, one can make a variable volatile so the compiler knows that other threads may be accessing it while the method is running and ensure the variable is preserved as the programmer intended (sans any optimizing effects).

    I guess I don't quite understand where volatile played a role in the current example. Once the user hits a return, something is done to ensure that the input characters are passed to the userInput variable. ThreadOne only loops once per user input and then checks to see if it needs to exit. ThreadTwo has no such constraint but it loops very fast and should eventually see "exit". At worst, the two threads might quit in different order. I could imagine a scenario where the characters are actually placed in the userInput variable as they are typed. Say the user typed "exit4". One thread might see "exit" and exit. The other thread might see "exit4" and not exit. Or they both could miss the "exit" and never quit. In that case, I would think synchronizing the assignment of the scanner input to the variable would be required to make the assignment really atomic.

    Unfortunately, the fact that the OP's example didn't work as intended for the OP implies that either my logic is flawed (or something else is going on that I don't know or understand).

    Regards,
    Jim
    The JavaTM Tutorials | SSCCE | Java Naming Conventions
    Poor planning on your part does not constitute an emergency on my part

Similar Threads

  1. how to share same object to multipule threads ?
    By reddi.java97 in forum Advanced Java
    Replies: 2
    Last Post: 09-11-2013, 09:21 PM
  2. Replies: 2
    Last Post: 04-10-2013, 12:46 AM
  3. Replies: 7
    Last Post: 12-07-2012, 01:00 PM
  4. Replies: 3
    Last Post: 02-11-2010, 09:59 AM
  5. Replies: 1
    Last Post: 08-01-2007, 09:25 PM

Posting Permissions

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