On Thu, 15 Jun 2006 16:44:25 +0100, Matthew Toseland wrote: > On Thu, Jun 15, 2006 at 01:03:20PM +0300, Jusa Saari wrote: >> On Thu, 15 Jun 2006 01:37:35 +0100, Matthew Toseland wrote: >> > There is, though we always start the thread at the end of the >> > constructor, and as I understand that page Thread.start() will flush >> > everything in the surrounding code first... >> >> That makes no difference - the code I saw also started the thread as the >> last thing in the constructor. From what I've understood the problem is >> that the "final" fields are not frozen until the constructor actually >> finishes, the compiler and JVM are free to rearrange the code inside the >> constructor for maximum efficiency (so the thread may actually be >> started before you think it would just from reading the source), and >> even if they didn't any subclass is going to call the superclass >> constructor as the first thing in its own constructor. > > Hmmm. The page said that thread start counts as exiting synchronization, > so this shouldn't happen.
You forget that the compiler or JVM may change the order of instructions. Just because the assignment to some field is before the Thread.start() in source code doesn't mean that this is so in the final machine code that gets executed. Or so I've understood, anyway; the point remains that every document I've read warns that starting threads from constructor, or placing a reference to the object being constructed anywhere where another thread might possibly see it, will cause problems. And, like I said, I've seen the resulting oddness in action. I think I'll go read the official JVM documentation; it should clear the matter once and for all. >> Anyway, no matter what the theoretical roots of the problem, I've seen >> it cause weird problems in other code, so it needs to be fixed. > > Indeed. >> >> > File a bug, or hack on it yourself. >> >> I'll look into it - I have some spare time, but I'm not very familiar >> with Freenet's codebase. > > http://bugs.freenetproject.org/ >> >> Anyway, there's at least two good models to fix this problem: the init() >> way and the factory way. >> >> The init() way simply includes additional method, init(), which starts >> the thread (and adds reference to the object to where ever it needs to >> be added - the construct *must not* leak references), so all object >> creations change from "new Object()" into "new Object().init()". It has >> the downside of leading to bugs if the programmer forgots to call >> init(), but it works well even if the class is subclassed, since the >> init() method is inherited. > > We use this in some places. >> >> The factory way is the good old trick of making the constructor >> protected, and providing a static method for getting new objects. That >> static method constructs the object, calls its (also protected) init >> method, and returns it. It has the downside of making subclassing a bit >> more complex - you need to override the factory method - but protects >> against anyone forgetting to call init() (or multiple calls to it, for >> that matter). > > This too sometimes. >> >> Which way would be preferable to use in Freenet ? I'd recommend factory, >> since there's less chances of anything going wrong since the programmer >> doesn't need to remember to call init(), but you're the professional >> programmer here :). > > :) > > Case by case perhaps? I'm friendly to both approaches. Given modern tools, > checking that the start()/init() method is called isn't difficult, but > factories can be useful sometimes. Um, isn't using one way somewhere and another way somewhere else the best way to ensure that someone will get it wrong somewhere ? Anyway, I'll look into the code and get back to you later. _______________________________________________ Devl mailing list [email protected] http://emu.freenetproject.org/cgi-bin/mailman/listinfo/devl
