Java Forum / General / April 2006
is this correct use of synchronized?
Jeff - 16 Apr 2006 12:50 GMT midp 2.0 Java SE 5.0 J2ME version 2.2
Is this correct use of synchronized? NB: methods like startApp are needed to get the code below to work, I know that....
public class Test extends MIDlet implements Runnable; { private boolean helloworld;
public Test() { helloworld = false; display = Display.getDisplay(this); Thread thread = new Thread(this); thread.start(); synchronized (this) { helloworld = false; } }
public void run() { synchronized (this) { helloworld = true; } } }
Jeroen V. - 16 Apr 2006 20:33 GMT http://www.google.be/search?q=synchronized+java
And there is R. Green his site
Chris Smith - 16 Apr 2006 20:54 GMT > http://www.google.be/search?q=synchronized+java > > And there is R. Green his site And there's this newsgroup, which I hope turns out to be a helpful resource for people who come here with questions. Pointing someone to a resource that helps with a question is one thing... but this was a question that is simply not answered by basically telling someone to go search Google, or by a vague reference to the Java Glossary. Thread synchronization problems in particular tend be of the type that require sophisticated reasoning, and a definition of what 'synchronized' does or examples from very different contexts are unlikely to be appropriate.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Jeroen V. - 17 Apr 2006 14:29 GMT >> http://www.google.be/search?q=synchronized+java >> >> And there is R. Green his site > > And there's this newsgroup, which I hope turns out to be a helpful > resource for people who come here with questions. Given the fact that the question is well documented.
> Pointing someone to a > resource that helps with a question is one thing... but this was a > question that is simply not answered by basically telling someone to go > search Google, or by a vague reference to the Java Glossary. Okay, maybe I should have asked what Jeff wanted to reach, but when you hope for an answer you should post questions that describe the problem & its context thoroughly. I could have answered "Is this correct use of synchronized?" with: "yes if it compiles"...
> Thread synchronization problems in particular tend be of the type that require > sophisticated reasoning, and a definition of what 'synchronized' does or > examples from very different contexts are unlikely to be appropriate. You're right, but as I stated before, in my opinion the context wasn't very clear.
Chris Smith - 16 Apr 2006 20:51 GMT > Is this correct use of synchronized?
> public class Test extends MIDlet implements Runnable; > { [quoted text clipped - 16 lines] > } > } What are you trying to do? Since the field 'helloworld' is never read in the code you posted, it would be difficult to classify the use as either "correct" or "incorrect". From what threads and from what code do you read the value of the 'helloworld' field?
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Jeff - 16 Apr 2006 21:55 GMT Thanks for your reply
I modified the code a bit, instead of showing an example code I instead posted a real scenario I've having problems with. My trouble is with the threads. the variable "scanning" is set to TRUE in void Scan() and the last thing done in the run() method is setting scanning = FALSE... the Paint method will print out TRUE to the debug window if scanning is TRUE, but it prints FALSE instead - it doesn't print TRUE even if the run is busy in the FOR-loop either.
I've been looking into this problem for a couple of days and I got stuck... I think this error is related to synchronization but I honestly cannot find out what is causing this problem. So please tell me what I must change in my code to make it work...
The method calling Scan isn't shown, but it's done when the user pushes the # key on the handset
This doesn't work when I compile and run it on emulator from Nokia.... I mean this code runs but it doesn't run as I want it to... I don't get any compile errors, if I get compile errors I wouldn't be able to run it...
package com.test;
import javax.microedition.lcdui.*; import javax.microedition.lcdui.game.*; import javax.microedition.media.*; import java.io.IOException; import java.io.InputStream; import java.util.*; import javax.microedition.io.*;
class testManager extends javax.microedition.lcdui.game.LayerManager implements Runnable { public boolean scanning = false; public testManager(int width, int height) throws Exception { }
//Methods public void paint(Graphics g) { synchronized (this) { if (scanning) { System.out.println("TRUE"); } else { System.out.println("FALSE"); } } paint(g, 0, 0); }
public void Scan() { strInfoText = "helloworld3"; synchronized (this) { scanning = true; } Thread thread = new Thread(this); thread.start(); }
public void run() { for (int i=0; i<10; i++) { System.out.println("TESTING " + i); } System.out.println("scan done"); synchronized (this) { scanning = false; } } }
>> Is this correct use of synchronized? > [quoted text clipped - 23 lines] > either "correct" or "incorrect". From what threads and from what code > do you read the value of the 'helloworld' field? Jon Martin Solaas - 17 Apr 2006 14:29 GMT > Thanks for your reply > [quoted text clipped - 5 lines] > prints FALSE instead - it doesn't print TRUE even if the run is busy in the > FOR-loop either. Generally synchronizing one atomic operation is meaningless. As far as I can tell, the usage of synchronized in this code does nothing.
> I've been looking into this problem for a couple of days and I got stuck... > I think this error is related to synchronization but I honestly cannot find [quoted text clipped - 3 lines] > The method calling Scan isn't shown, but it's done when the user pushes the > # key on the handset So we have one instance of testManager (should be TestManager, really, and methods should start with lowercase instead ... ), and one thread running the Scan method, or could # be pushed several times spawning several threads? Let's assume that's a possibility.
> This doesn't work when I compile and run it on emulator from Nokia.... I > mean this code runs but it doesn't run as I want it to... I don't get any > compile errors, if I get compile errors I wouldn't be able to run it... When scanning is set to true or false within a synchronized block, there is nothing preventing some other thread to re-set it to something else immediately after the last instruction in the synchronized block has completed.
If the user pushes # two times the first thread will set scanning=true and the second thread will do the same at a slightly later point in time. Then the first thread will end the for-loop, set scanning=false and terminate. The second thread may still be running in the for-loop in the scanning method, while scanning actually is false already. If paint is called at this point the output would be FALSE.
> package com.test; > [quoted text clipped - 45 lines] > } > } try this
Boolean scanning = new Boolean(false);
public void scan() { Thread thread = new Thread(this); thread.start(); }
public void run() { synchronized(scanning) { scanning=new Boolean(true); for (int i = 0; i < maxScan; i++) { Scanner.scan(i); System.err.println("Now scanning i = " + i); } System.err.println("Done scanning"); scanning=new Boolean(false); } } Any code accessing the scanning variable in this instance of the testManager class will see the false value because scanning is only true within the synchronized block where other code is locked out from accessing the object scanning (it needs to be Boolean and not boolean to lock it). Ofcourse this is under assumption that the scanning variable is not set to true somewhere else in the code outside the synchronized block.
I'm not at all sure this is really what you need to do, I know too little of what your app is really doing. Maybe this will introduce new locking problems for you.
 Signature jon martin solaas
Thomas Hawtin - 17 Apr 2006 14:22 GMT > Generally synchronizing one atomic operation is meaningless. As far as I > can tell, the usage of synchronized in this code does nothing. Not really. It allows other threads to access data in a more complex way. Also without volatile/synchronisation, you have no happens-before relationships, so don't know when other threads will see changes. You can also create an object outside of a synchronised block and update a reference to it within such a block, and still end up with everything properly synchronised.
Tom Hawtin
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
Jon Martin Solaas - 17 Apr 2006 15:48 GMT >> Generally synchronizing one atomic operation is meaningless. As far as >> I can tell, the usage of synchronized in this code does nothing. [quoted text clipped - 7 lines] > > Tom Hawtin That was all very blurry to me. But I'm no synchronization wizard. Would you care to explain in detail what would be the difference if all the synchronization blocks in the code in this news-thread (not execution thread :-) were removed? Exactly what's the difference between
scanning=false;
and
synchronized (this) { scanning=false; }
?
What kind of happens-before-relationships are present in the latter, but not in the first part here (or in the posted code if this example is to simple)?
 Signature jon martin solaas
Gordon Beaton - 17 Apr 2006 16:30 GMT > Exactly what's the difference between > [quoted text clipped - 9 lines] > but not in the first part here (or in the posted code if this > example is to simple)? Assuming that the assigment is atomic, there is still no guarantee that a thread reading the value of scanning will see the latest assigned value unless there is a barrier between the assignment and the subsequent read. You get a barrier by declaring the variable "volatile" or accessing it from within a synchronized block.
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
Chris Smith - 17 Apr 2006 16:36 GMT > That was all very blurry to me. But I'm no synchronization wizard. Would > you care to explain in detail what would be the difference if all the [quoted text clipped - 10 lines] > > ? The difference is that with the first, there's no guarantee at all as to when another thread that reads 'scanning' will see its value as false. With the latter, any thread that enters a synchronization block on the object first and THEN reads 'scanning' is guaranteed to see its value as being false.
This is not an easy thing to understand, unfortunately. The chapter of the JLS that explains it is one of the most difficult in the whole book (perhaps not quite so bad as the part about type inference for generic method invocations without explicit type arguments). In essence, though, when evaluating multithreading correctness you should stop thinking in terms of a variable having only one value. It may have a different value from the perspective of any thread; and it may have any number of values, of which the variable may evaluate to any of them, arbitrarily, when used as a value. The only way to avoid this is to use the volatile or synchronized keywords. In this case, volatile would have been sufficient. However, synchronized works as well.
What synchronized does is to establish a "happens-before" relationship. That simply means that one action of the code is guaranteed to have happened before another, and the results of the first statement are therefore visible to the second. Entering or leaving a synchronized block establishes such a "happens-before" relationship with another thread that enters or leaves that same block. Therefore, the values written to variables from the first thread are visible to the second. Without the synchronization actions, there would be no such relationships and it would be entirely possible for the second thread to continue to read whatever value 'scanning' had when the thread was started. (Because thread creation DOES establish such a "happens- before" relatonship, it would not be possible for the second thread to read a value of scanning from some time before the thread creation.)
> What kind of happens-before-relationships are present in the latter, but > not in the first part here (or in the posted code if this example is to > simple)? The original code without the synchronized statements establishes only one significant happens-before relationship: namely, that the call to thread.start() happens-before the first action of the new thread. There are a HUGE number of other such relationships, due to the fact that within a single thread each action of code happens-before any action of code that comes after it; either in order of operations within an expression, or in a subsequent statement. However, it's easier to not mention those until they are needed, considering them obvious.
The code with the synchronized statement establishes those happens- before relationships, plus additional happens-before relationships that say that one thread exiting a synchronized block happens-before another thread entering that block. These additional relationships are neeeded to guarantee that changes to the 'scanning' variable made from run() (and perhaps from Scan() if it's not called from the graphics thread) are visible inside of paint(Graphics).
Does that help, or confuse you more?
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Jon Martin Solaas - 17 Apr 2006 17:33 GMT > Does that help, or confuse you more? Both :-)
Jon Martin Solaas - 17 Apr 2006 17:36 GMT > Does that help, or confuse you more? PS, and more importantly, what is the exact problem with the code from OP? He has the synchronized blocks and still doesn't get the expected result.
 Signature jon martin solaas
Jeff - 17 Apr 2006 18:43 GMT Thanks for your help, I've done a few changes to the 'run' method and still I have the same problem, I've been testing this code for a while and it seems like while the 'run' method is running the 'paint' method is called many times. the 'paint' method reads 'scanning' as FALSE, while 'run' is running and 'scanning' have got the value TRUE inside 'run'....
package com.test;
import javax.microedition.lcdui.*; import javax.microedition.lcdui.game.*; import javax.microedition.media.*; import java.io.IOException; import java.io.InputStream; import java.util.*; import javax.microedition.io.*;
class testManager extends javax.microedition.lcdui.game.LayerManager implements Runnable { public boolean scanning = false; public testManager(int width, int height) throws Exception { }
//Methods public void paint(Graphics g) { synchronized (this) { if (scanning) { System.out.println("TRUE"); } else { System.out.println("FALSE"); } } paint(g, 0, 0); }
public void Scan() { strInfoText = "helloworld3"; synchronized (this) { scanning = true; } Thread thread = new Thread(this); thread.start(); }
public void run() { synchronized (this) { if (scanning) { for (int i=0; i<10; i++) { System.out.println("TESTING " + i); } System.out.println("scan done"); scanning = false; } } } }
This code generate this output to the debug window.... The FALSE are written by the paint method.....
FALSE FALSE TESTING 0 TESTING 1 TESTING 2 TESTING 3 TESTING 4 TESTING 5 TESTING 6 TESTING 7 TESTING 8 TESTING 9 scan done FALSE FALSE FALSE FALSE FALSE
But when I modified run, removed this statement: scanning = false;
Now the result gets as shown below
FALSE FALSE FALSE FALSE TESTING 0 TESTING 1 TESTING 2 TESTING 3 TESTING 4 TESTING 5 TESTING 6 TESTING 7 TESTING 8 TESTING 9 scan done TRUE TRUE
In my humble opinion this means that this statement : synchronized (this) { scanning = true; } works okay....
BUT, while the 'run' method is running the 'paint' method is called many times. the 'paint' method reads 'scanning' as FALSE, while 'run' is running and 'scanning' have got the value TRUE inside 'run'....
What must I change so that the 'paint' reads the value 'scanning' have while 'run' is running?
Jeff
Jeff - 18 Apr 2006 14:50 GMT public void run() { synchronized (this) { if (scanning) { for (int i=0; i<10; i++) { System.out.println("TESTING " + i); } System.out.println("scan done"); scanning = false; } } }
It seems like 'scanning = false;' get executed before the for-loop. To me this is very strange behavior, 'scanning = false;' is under the for-loop and I thought that the for-loop would be executed before the 'scanning = false;' statment
If I remove the statment 'scanning = false;' from 'run' then it works, I mean that while the for-loop is executing the 'paint' method reads the value 'scanning' has before set to FALSE, in other words it reads the value TRUE
But if the statment 'scanning = false;' is removed the program can't tell when the thread is done executing...I want 'scanning' to be set back to FALSE when the for-loop is finished OR when the thread is done executing
maybe using wait(), notify() or notifyAll() can help???, I'm not sure how to apply them....
I'm not sure how to fix this so I would appreciate any tips helping me solve this problem
Jeff
> Thanks for your help, I've done a few changes to the 'run' method and > still I have the same problem, I've been testing this code for a while and [quoted text clipped - 113 lines] > > Jeff Chris Smith - 18 Apr 2006 16:08 GMT > public void run() { > synchronized (this) { [quoted text clipped - 9 lines] > > It seems like 'scanning = false;' get executed before the for-loop. No, it gets executed after the for loop. The problem is that no paint calls can finish until the for loop is done, since the entire loop is in a synchronized block and paint contests for that same monitor. So once the new thread you're creating successfully gains the monitor, it doesn't let go and let a paint happen until after it has set scanning back to false again.
Unfortunately, we're dealing with a very vague situation here. I'm not clear on what behavior you actually want to see, so it's hard to make recommendations on how to get there. However, one possibility may be that you only want to obtain a synchronized block around the assignment to the scanning variable, rather than around the entire loop.
> maybe using wait(), notify() or notifyAll() can help???, I'm not sure how to > apply them.... I haven't seen anything YET that suggests these would be needed; but you're also a long way from my understanding what you want to do.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Jeff - 18 Apr 2006 18:22 GMT Hey, thanks for your post!
I modified 'run' a bit, see below.... now a copy of 'scanner' is created in the first synchronized block and the rest of the method uses this copy ... the last thing this method now does is establishing a synchronized block and set the 'scanner' back to false;
What I'm trying to do is that while this midlet is running a status line at the bottom of the screen, I want this status line to show the status about the midlet is doing.... So when 'scanner' is TRUE I want it to display a text telling it is doing this 'run' method....
Any suggestion to what I must change in my code so that 'paint' draw the correct status will be greatly appreciated. What status the 'paint' draw is directly related to the 'scanner' variable, because a if-test in 'paint' determine what will be displayed - if (scanner) {
public void run() { boolean ecopy; synchronized (this) { ecopy = scanning; } if (ecopy) { for (int i=0; i<10; i++) { System.out.println("TESTING " + i); } System.out.println("scan done"); synchronized (this) { scanning = false; } } } }
>> public void run() { >> synchronized (this) { [quoted text clipped - 29 lines] > I haven't seen anything YET that suggests these would be needed; but > you're also a long way from my understanding what you want to do.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|