|
|||||
|
|
#1 |
|
|
Is the following code correct ? public cl*** CDummy2 extends Thread { Integer threadId; CDummy2(Integer threadId) { this.threadId = threadId;} public static void main(String args[]) { System.out.println("CDummy2."); CDummy2 cd1 = new CDummy2(new Integer(1)); CDummy2 cd2 = new CDummy2(new Integer(2)); System.out.println("Starting thread 1..."); cd1.start(); try { Thread.sleep(250); } catch(InterruptedException ee) { System.out.println("The thread was interrupted !"); } System.out.println("Starting thread 2..."); cd2.start(); } public void run() { int ii = 50; while(ii-- > 0) { printData("threadId: " + threadId + ", ii=" + ii); try { Thread.sleep(100); } catch(InterruptedException ee) { System.out.println("The thread was interrupted !"); } } } void printData(String input) { synchronized (threadId) { System.out.println(input); } } } I am synchronizing 2 threads on the Integer 'threadId'. Since the code is trivial it seems to work. However, each thread cl*** has its own threadId. Since the object is not common for the 2 threads, that means no synchronization is taking place in the method printData(). The only solution that I can think of is to make the threadId static. Being static all the threads will share the same static object thus synchronization should occur. If my observation is correct that means that you can only synchronize on cl*** (static) variables but not on member variables. My head is spinning. I am thinking to this for over 1 hour. There should be a very simple explanation. Regards, Razvan |
|
|
#2 |
|
|
> > [code snipped; see up-thread] > > I am synchronizing 2 threads on the Integer 'threadId'. Since the > code is trivial it seems to work. However, each thread cl*** has its > own threadId. Since the object is not common for the 2 threads, that > means no synchronization is taking place in the method printData(). > > The only solution that I can think of is to make the threadId static. > Being static all the threads will share the same static object thus > synchronization should occur. > > If my observation is correct that means that you can only synchronize > on cl*** (static) variables but not on member variables. > > My head is spinning. I am thinking to this for over 1 hour. There > should be a very simple explanation. You can synchronize on any Object at all. It doesn't matter whether the references to the Object are static variables, member variables, or even method-local variables. The "thing" on which you synchronize is the Object that is the target of the reference. ... and that's the key to understanding why and when to synchronize. Synchronization is not about monopolizing the use of a chunk of code, but about monopolizing the use of an Object. Consider the Vector cl*** for a moment, as an example of a familiar cl*** that uses synchronization. It would be a Bad Thing if two threads both ran the add() method on the same Vector at the same time, but it's perfectly all right -- desirable, in fact -- that two threads be able to run add() on two different Vectors simultaneously. You don't want to prevent multiple simultaneous executions of add(); that would just make the program run more slowly than it should. And it wouldn't make the program correct, either! If thread T1 runs add() at the same time T2 is running remove() on the same Vector, there's only one add() running and only one remove() running, but clearly there's trouble in store. You don't want to prevent simultaneous execution of a region of code, you want to prevent simultaneous manipulation of an object. In the above example, both the add() and remove() methods synchronize on the Vector they're manipulating: this means that one of them will wait until the other is finished, so the Vector is being manipulated by only one thread at a time. Meanwhile, other threads can call add() and remove() on other Vectors without interference. Synchronization is about protecting the object, not about protecting the code. With that in mind, reconsider what you're trying to do. You've got a method that synchronizes on an Integer. As it happens, the only reference to that Integer is embedded in the object itself; no other thread can get at the Integer and hence synchronization accomplishes nothing. That's most likely not the effect you were looking for, but I don't know what you're actually trying to achieve. -- Eric.Sosman@sun.com |
|
|
#3 |
|
|
"Razvan" <mihai11@mailcity.com> wrote in message news:15f19d61.0408310813.4b0f1403@posting.google.c om... > Hi > > Is the following code correct ? /snip/ > > I am synchronizing 2 threads on the Integer 'threadId'. Since the > code is trivial it seems to work. However, each thread cl*** has its > own threadId. Since the object is not common for the 2 threads, that > means no synchronization is taking place in the method printData(). > > The only solution that I can think of is to make the threadId static. > Being static all the threads will share the same static object thus > synchronization should occur. > > If my observation is correct that means that you can only synchronize > on cl*** (static) variables but not on member variables. You cannot synch on variables or fields, only on objects. A variable or a field may have a reference to an object. If thread T1 synchs on variable "fubar", and thread T2 synchs on field "snafu", then they are synch'd with each if and only if the contents of "fubar" and "snafu" refer to the same object. You can use an initialized static field, or you can p*** a reference to a mutex object in the constructor of the subcl***. (I also suggest that you do not extend Thread, but use the Thread(Runnable) constructor. It's much more powerful and flexible than extending Thread.) > My head is spinning. I am thinking to this for over 1 hour. There > should be a very simple explanation. You can also use a shared mutex (Mutual Exclusion) object. http://mindprod.com/products.html http://mindprod.com/zips/java/mutex10.zip -- ---------------------------- Jeffrey D. Smith Farsight Systems Corporation 24 BURLINGTON DRIVE LONGMONT, CO 80501-6906 http://www.farsight-systems.com z/Debug debugs your Systems/C programs running on IBM z/OS for FREE! |
|
|
#4 |
|
|
Eric Sosman coughed up:
> Razvan wrote: >> >> [code snipped; see up-thread] >> >> I am synchronizing 2 threads on the Integer 'threadId'. Since the >> code is trivial it seems to work. However, each thread cl*** has its >> own threadId. Since the object is not common for the 2 threads, that >> means no synchronization is taking place in the method printData(). >> >> The only solution that I can think of is to make the threadId static. >> Being static all the threads will share the same static object thus >> synchronization should occur. >> >> If my observation is correct that means that you can only synchronize >> on cl*** (static) variables but not on member variables. >> >> My head is spinning. I am thinking to this for over 1 hour. There >> should be a very simple explanation. > > You can synchronize on any Object at all. It doesn't > matter whether the references to the Object are static > variables, member variables, or even method-local variables. > The "thing" on which you synchronize is the Object that is > the target of the reference. > > ... and that's the key to understanding why and when to > synchronize. Synchronization is not about monopolizing the > use of a chunk of code, but about monopolizing the use of > an Object. Consider the Vector cl*** for a moment, as an > example of a familiar cl*** that uses synchronization. It > would be a Bad Thing if two threads both ran the add() method > on the same Vector at the same time, but it's perfectly all > right -- desirable, in fact -- that two threads be able to run > add() on two different Vectors simultaneously. You don't want > to prevent multiple simultaneous executions of add(); that would > just make the program run more slowly than it should. And it > wouldn't make the program correct, either! If thread T1 runs > add() at the same time T2 is running remove() on the same Vector, > there's only one add() running and only one remove() running, > but clearly there's trouble in store. > > You don't want to prevent simultaneous execution of a > region of code, you want to prevent simultaneous manipulation > of an object. In the above example, both the add() and remove() > methods synchronize on the Vector they're manipulating: this > means that one of them will wait until the other is finished, > so the Vector is being manipulated by only one thread at a time. > Meanwhile, other threads can call add() and remove() on other > Vectors without interference. > > Synchronization is about protecting the object, not about > protecting the code. uh.................... You seem to understand this issue very well, but you've used a sentence that I'd never suggest anyone use. Synchronization is about protecting sections of code. Whether or not there is an object involved to be protected as such is secondary. The object used can merely be to "hold the lock". For example, public cl*** YoiksAndAwayWham { Object lock = new Object(); ... void dangerousThingy() { ....lots of safe stuff... synchronized(lock) { ...stuff not protecting current object, nor protecting "lock" but meant to protect this section of code from collision with other similar methods. Protecting YoiksAndAwayWham instances may never even enter the picture... } } void anotherDangerousThingy() { ....lots of safe stuff... synchronized(lock) { ...stuff not protecting current object, nor protecting "lock" but meant to protect this section of code from collision with other similar methods. Protecting YoiksAndAwayWham instances may never even enter the picture... } } } > > With that in mind, reconsider what you're trying to do. > You've got a method that synchronizes on an Integer. As it > happens, the only reference to that Integer is embedded in > the object itself; no other thread can get at the Integer > and hence synchronization accomplishes nothing. That's most > likely not the effect you were looking for, but I don't know > what you're actually trying to achieve. -- Onedoctortoanother:"Ifthisismyrectalthermometer,wh erethehell'smypen???" |
|
|
#5 |
|
|
Thomas G. Marshall coughed up:
> Eric Sosman coughed up: >> Razvan wrote: >>> >>> [code snipped; see up-thread] >>> >>> I am synchronizing 2 threads on the Integer 'threadId'. Since the >>> code is trivial it seems to work. However, each thread cl*** has its >>> own threadId. Since the object is not common for the 2 threads, that >>> means no synchronization is taking place in the method printData(). >>> >>> The only solution that I can think of is to make the threadId >>> static. Being static all the threads will share the same static >>> object thus synchronization should occur. >>> >>> If my observation is correct that means that you can only >>> synchronize on cl*** (static) variables but not on member variables. >>> >>> My head is spinning. I am thinking to this for over 1 hour. There >>> should be a very simple explanation. >> >> You can synchronize on any Object at all. It doesn't >> matter whether the references to the Object are static >> variables, member variables, or even method-local variables. >> The "thing" on which you synchronize is the Object that is >> the target of the reference. >> >> ... and that's the key to understanding why and when to >> synchronize. Synchronization is not about monopolizing the >> use of a chunk of code, but about monopolizing the use of >> an Object. Consider the Vector cl*** for a moment, as an >> example of a familiar cl*** that uses synchronization. It >> would be a Bad Thing if two threads both ran the add() method >> on the same Vector at the same time, but it's perfectly all >> right -- desirable, in fact -- that two threads be able to run >> add() on two different Vectors simultaneously. You don't want >> to prevent multiple simultaneous executions of add(); that would >> just make the program run more slowly than it should. And it >> wouldn't make the program correct, either! If thread T1 runs >> add() at the same time T2 is running remove() on the same Vector, >> there's only one add() running and only one remove() running, >> but clearly there's trouble in store. >> >> You don't want to prevent simultaneous execution of a >> region of code, you want to prevent simultaneous manipulation >> of an object. In the above example, both the add() and remove() >> methods synchronize on the Vector they're manipulating: this >> means that one of them will wait until the other is finished, >> so the Vector is being manipulated by only one thread at a time. >> Meanwhile, other threads can call add() and remove() on other >> Vectors without interference. >> >> Synchronization is about protecting the object, not about >> protecting the code. > > uh.................... You seem to understand this issue very well, > but you've used a sentence that I'd never suggest anyone use. > > Synchronization is about protecting sections of code. Whether or not > there is an object involved to be protected as such is secondary. > The object used can merely be to "hold the lock". > > For example, > > public cl*** YoiksAndAwayWham > { > Object lock = new Object(); static Object lock = new Object(); That is a better example for a newbie. The other way allows for multiple yoiks /each/ with their own handful of threads accessing them, which was the example I was going for. But that would be a disaster for a newbie, since it adds a layer of complexity not needed here. I'm sorry. > > ... > > void dangerousThingy() > { > ....lots of safe stuff... > synchronized(lock) > { > ...stuff not protecting current object, nor > protecting "lock" but meant to protect this > section of code from collision with other similar > methods. Protecting YoiksAndAwayWham instances > may never even enter the picture... > } > } > > void anotherDangerousThingy() > { > ....lots of safe stuff... > synchronized(lock) > { > ...stuff not protecting current object, nor > protecting "lock" but meant to protect this > section of code from collision with other similar > methods. Protecting YoiksAndAwayWham instances > may never even enter the picture... > } > } > } > > > > > > >> >> With that in mind, reconsider what you're trying to do. >> You've got a method that synchronizes on an Integer. As it >> happens, the only reference to that Integer is embedded in >> the object itself; no other thread can get at the Integer >> and hence synchronization accomplishes nothing. That's most >> likely not the effect you were looking for, but I don't know >> what you're actually trying to achieve. -- It'salwaysbeenmygoalinlifetocreateasignaturethaten dedwiththeword"blarphoogy" .. |
|
|
#6 |
|
|
Thomas G. Marshall wrote:
> Eric Sosman coughed up: > >> Synchronization is about protecting the object, not about >>protecting the code. > > uh.................... You seem to understand this issue very well, but > you've used a sentence that I'd never suggest anyone use. > > Synchronization is about protecting sections of code. Whether or not there > is an object involved to be protected as such is secondary. The object used > can merely be to "hold the lock". > > For example, > > public cl*** YoiksAndAwayWham > { > Object lock = new Object(); > > ... > > void dangerousThingy() > { > ....lots of safe stuff... > synchronized(lock) > { > ...stuff not protecting current object, nor protecting > "lock" but meant to protect this section of code from > collision with other similar methods. Protecting > YoiksAndAwayWham instances may never even > enter the picture... > } > } > > void anotherDangerousThingy() > { > ....lots of safe stuff... > synchronized(lock) > { > ...stuff not protecting current object, nor protecting > "lock" but meant to protect this section of code from > collision with other similar methods. Protecting > YoiksAndAwayWham instances may never even > enter the picture... > } > } > } In what way can the synchronized blocks (in this example or in your follow-up with a static lock) "collide?" The code is immutable whenever it's executable (that is, from the time it's been loaded to the time when it's unloaded, if ever), so it doesn't seem to be in need of much protection ... The only kind of "collision" I can envision is if the two pieces of code both manipulate some kind of shared resource. Usually, that resource is a Java Object, and the Object is the thing that needs the protection. Sometimes the resource is something outside Java, so Java cannot protect it: Java cannot synchronize access to an on-disk file, for example. But almost invariably any such extra-Java resource will have a Java Object acting as its "proxy," and you protect the actual resource by "protecting" its proxy: you synchronize on the File object that represents the file on disk. Sometimes the shared resource has little physical reality. You might be generating output with System.out.print() calls, for example, and trying to ensure that the output from different threads doesn't get intermixed on a single line. The synchronized blocks in your example would contain several System.out.print() calls followed by System.out.println(), and synchronization would prevent intermixture. You might want to think of this as protecting the code, but to me it seems more useful to think of the lock object as a proxy for "the current line," a resource outside Java that Java manipulates through the System.out object. (You could, I suppose, use the System.out object itself for this purpose -- I wouldn't, myself, but it "should" work, I think.) One of the characteristics of object-oriented programming is that it has (duh...) an object-centric orientation rather than a code-centric orientation. That being the case, it seems far more natural to think about protecting the objects than about which disparate pieces of code are or are not running simultaneously. It happens that I find this viewpoint helpful when thinking about synchronization in non-O-O languages, too -- but for an O-O language it seems almost a foregone conclusion that one would think in this way. YMMV. -- Eric.Sosman@sun.com |
|
|
#7 |
|
|
Razvan wrote:
> Hi > <snip> > > > I am synchronizing 2 threads on the Integer 'threadId'. Since the > code is trivial it seems to work. However, each thread cl*** has its > own threadId. Since the object is not common for the 2 threads, that > means no synchronization is taking place in the method printData(). > Right. > The only solution that I can think of is to make the threadId static. > Being static all the threads will share the same static object thus > synchronization should occur. > > If my observation is correct that means that you can only synchronize > on cl*** (static) variables but not on member variables. > That's not strictly true. To make code blocks exclusive, they must synchronize on the same Object, but this need not be by a static reference. It could be an Object handed as a method argument, or returned from another Object.method, e.g. myHashMap.get("BackDoorLock"); Actually, a dirty trick using interned String constants goes like this: synchronized("BackDoorLock") { ... } Actually, I recommend not extending Thread, but always using Runnable objects instead. This is because it gets very confusing when you start to synchronize by having one Thread subcl*** trying to lock on a different Thread subcl***'s member Objects or call another Thread subcl***'s methods. It's simpler if there are just Runnables that may be visited by more than one thread than if a Thread is being visited by a different Thread's thread. If that makes any sense. Steve |
|
|
#8 |
|
|
Eric Sosman coughed up:
> Thomas G. Marshall wrote: >> Eric Sosman coughed up: >> >>> Synchronization is about protecting the object, not about >>> protecting the code. >> >> uh.................... You seem to understand this issue very well, >> but you've used a sentence that I'd never suggest anyone use. >> >> Synchronization is about protecting sections of code. Whether or >> not there is an object involved to be protected as such is >> secondary. The object used can merely be to "hold the lock". >> >> For example, >> >> public cl*** YoiksAndAwayWham >> { >> Object lock = new Object(); >> >> ... >> >> void dangerousThingy() >> { >> ....lots of safe stuff... >> synchronized(lock) >> { >> ...stuff not protecting current object, nor >> protecting "lock" but meant to protect this >> section of code from collision with other >> similar methods. Protecting YoiksAndAwayWham >> instances may never even enter the picture... >> } >> } >> >> void anotherDangerousThingy() >> { >> ....lots of safe stuff... >> synchronized(lock) >> { >> ...stuff not protecting current object, nor >> protecting "lock" but meant to protect this >> section of code from collision with other >> similar methods. Protecting YoiksAndAwayWham >> instances may never even enter the picture... >> } >> } >> } > > In what way can the synchronized blocks (in this example > or in your follow-up with a static lock) "collide?" The code > is immutable whenever it's executable (that is, from the time > it's been loaded to the time when it's unloaded, if ever), so > it doesn't seem to be in need of much protection ... And how on earth do you know what threads are involved here? What if: The first method is called within one thread. The 2nd in another. Both of these access something that just cannot be accessed by more than one. This can involve something as innocuous as simple arithmetic on an integer primitive. Multiple threads doing very simple non-atomic things all at once can result in unpredictable results. > The only kind of "collision" I can envision is if the two > pieces of code both manipulate some kind of shared resource. > Usually, that resource is a Java Object, and the Object is > the thing that needs the protection. It can be several objects, or simply an algorithm that cannot be interrupted. But it's not about saving the objects involved. It's about keeping multiple executions of segments of code blocked until one execution is done. > Sometimes the resource > is something outside Java, so Java cannot protect it: Java > cannot synchronize access to an on-disk file, for example. > But almost invariably any such extra-Java resource will have > a Java Object acting as its "proxy," and you protect the > actual resource by "protecting" its proxy: you synchronize > on the File object that represents the file on disk. > > Sometimes the shared resource has little physical reality. > You might be generating output with System.out.print() calls, > for example, and trying to ensure that the output from > different threads doesn't get intermixed on a single line. > The synchronized blocks in your example would contain several > System.out.print() calls followed by System.out.println(), > and synchronization would prevent intermixture. That is the precise example I use when I teach java. > You might want > to think of this as protecting the code, And you should. "protection" has a great many meanings. It seems that you are comfortable saying that anything that allows an algorithm to stay functional is protecting the objects. But your statements go beyond that. The object is not what is protected, it is a section of code. That may result in objects behaving properly. > but to me it seems more > useful to think of the lock object as a proxy for "the current > line," a resource outside Java that Java manipulates through the > System.out object. This makes no sense whatsoever. > (You could, I suppose, use the System.out > object itself for this purpose -- I wouldn't, myself, but it > "should" work, I think.) > > One of the characteristics of object-oriented programming > is that it has (duh...) an object-centric orientation rather > than a code-centric orientation. No, it has object orientation rather than /procedural/ orientation. "code" lives in both paradigms. Wow, you're all over the map on this post. > That being the case, it seems > far more natural to think about protecting the objects than > about which disparate pieces of code are or are not running > simultaneously. It happens that I find this viewpoint helpful > when thinking about synchronization in non-O-O languages, too -- > but for an O-O language it seems almost a foregone conclusion > that one would think in this way. YMMV. It is not the object in total that is protected. It is a section of code that you specifically force blockage into. If you instruct people to think that synchronization is protecting objects, then you are misleading them horribly. The bottom line is not that they are objects. The bottom line is that a section of executable code is protected from re-entrance by another thread. -- "It's easier to be terrified by an enemy you admire." -Thufir Hawat, Mentat and Master of ******ins to House Atreides |
|
|
#9 |
|
|
Steve Horsley coughed up:
> Razvan wrote: >> Hi >> > <snip> >> >> >> I am synchronizing 2 threads on the Integer 'threadId'. Since the >> code is trivial it seems to work. However, each thread cl*** has its >> own threadId. Since the object is not common for the 2 threads, that >> means no synchronization is taking place in the method printData(). >> > > Right. > >> The only solution that I can think of is to make the threadId static. >> Being static all the threads will share the same static object thus >> synchronization should occur. >> >> If my observation is correct that means that you can only synchronize >> on cl*** (static) variables but not on member variables. >> > > That's not strictly true. To make code blocks exclusive, they must > synchronize on the same Object, but this need not be by a static > reference. It could be an Object handed as a method argument, or > returned from > another Object.method, e.g. myHashMap.get("BackDoorLock"); > > Actually, a dirty trick using interned String constants goes like > this: > > synchronized("BackDoorLock") { > ... > } > > Actually, I recommend not extending Thread, but always using Runnable > objects instead. This is because it gets very confusing when you start > to synchronize by having one Thread subcl*** trying to lock on a > different Thread subcl***'s member Objects or call another Thread > subcl***'s methods. It's simpler if there are just Runnables that may > be visited by more than one thread than if a Thread is being visited > by a different Thread's thread. If that makes any sense. > > Steve For similar reasons I *strongly* recommend that a newbie not use synchronized methods such as: public synchronized void hoohaa() { //...goblidy gook... } but instead use public void hoohaa() { synchronized (myLock) { //...goblidy gook... } } and have myLock be an Object instance devoted to nothing but holding the lock. The reason for this is important: a. it keeps the confusion down in general about whether or not a lock is held by the same instance as used elsewhere. b. it keeps the following bug out. This bug I've seen time and time again: someone tries to add a synchronized method, but later makes it static for some other reason. But he forgets that synchronized then is locking on the cl*** object when used with static. Two locks in that case. <bug> public synchronized void hoohaa() { } //and then someday someone adds this: public static synchronized void anotherMethod() { // not protected against hoohaa() collisions... } </bug> -- "It's easier to be terrified by an enemy you admire." -Thufir Hawat, Mentat and Master of ******ins to House Atreides |
|
|
#10 |
|
|
Thomas G. Marshall wrote:
> It is not the object in total that is protected. It is a section of code > that you specifically force blockage into. If you instruct people to > think that synchronization is protecting objects, then you are misleading > them horribly. The bottom line is not that they are objects. The bottom > line is that a section of executable code is protected from re-entrance > by another thread. I disagree with this completely. First off, it is not -- no matter what your stance on OO, or even whether you are using an OO language -- code that is being protected, it is /state/. There are one or more variables whose values must be "managed" to allow correct concurrent access. So at minimum it is misleading to talk of protecting code, you should be talking about protecting data. Now in the OO world (and I'll accept, that Java is OO in this matter), data/state is normally bunched into semantically coherent units called objects. So the most natural thing to do is to manage concurrency at the level of the overall state of one object. In that case we are clearly using synchronisation to protect the (state of) the object. Just as Eric says. And the normal way to express that is with code synchronised on 'this' -- synchronised methods for instance. Now in some cases, the state that needs to be protected will be either distributed across more than one object, or be less than the entire state of an object. Such cases are rare -- as you'd expect because the object is (or should be) expressing a semantically coherent unit of state, and the protection will normally be expected to follow the same boundaries, precisely /because/ it is protecting semantic coherence. Still, such cases do occur, and in those cases, and /only/ in those cases, your more "advanced" technique of using a lock object is appropriate. BTW, I don't think "lock" is a good name for a lock object. For the reasons given above, it is misleading to use it to protect exactly the state of 'this'. So either it is being used as a shared lock -- to act as a "channel" whereby two or more objects can maintain some semantic interdependency. In such cases, I would submit that "sharedLock" is the minimum meaningful name. OTOH, you may have an object that only needs to protect some of its state. Offhand, I can't think of a convincing example, but say that an object needs to protect its output logging stream, and independently needs to protect the state of its interaction with some network server; in such cases it seems that the minimum meaningful names would be loggingLock and networkLock. The occurrence of the undecorated name "lock" is an indication that the author may not have understood what s/he was doing. (As, BTW, is casually moving a method between static and non-static -- that is a change at least as great, in OO terms, as moving a method between cl***es since it is changing the behaviour of two objects (treating the 'cl***' as if it were an object for these purposes).) -- chris |