Prev: Immediate Start: Need Designer's (Visual/Graphic),Beverly Hills,California,
Next: Ordering of hashtable keys
From: Lew on 18 Jul 2010 01:17 Lew wrote: >>>> String is the most basic immutable class in the API. Tom Anderson wrote: >>> Object? Lew wrote: >> You're tardy to the party on that one. Asked and answered and driven >> to the depths of absurdity upthread already. Tom Anderson wrote: > Again, again! Okay. The upshot was: Eric Sosman wrote: >> (Prediction: Lew's answer will be "Yes," accompanied by a treatise >> on the philosophic phylogeny of para-abstract psycho-paradigms, which >> no one will be able to follow -- not even Lew!) Lew wrote: > It depends on the ontological semantics of "basic". Beginning Java > programmers typically are introduced to the use of 'String' well > before 'Integer' so in a pedagogical sense 'String' is the more basic > type. Of course, within the para-abstract psycho-paradigm of inherent > basicity, no one could argue for 'String' over 'Integer'. -- Lew
From: Jim Janney on 18 Jul 2010 04:29 Andreas Leitgeb <avl(a)gamma.logic.tuwien.ac.at> writes: > Jim Janney <jjanney(a)shell.xmission.com> wrote: >> Peter Duniho <NpOeStPeAdM(a)NnOwSlPiAnMk.com> writes: >>> I mean sure, there are ways that it could have been written >>> incorrectly. The main (only?) non-thread-safe mistake being to use >>> the "hash" field itself as the accumulator for the calculation. >> >> public class SannyCode { >> [ uses the "hash" field itself as the accumulator for the calculation.] >> } > > That's the one sin which Pete already mentioned. OK, here's a version that doesn't do that. public class SannyCode { private final String s; private boolean calculated = false; private long code = 0; public SannyCode(String s) { this.s = s; } public long getCode() { if (!calculated) { calculated = true; long c = 0; for (int i = s.length() - 1; i >= 0; i--) { if (s.charAt(i) != '-') { c += i; } } code = c; } return code; } } Still not thread-safe. In any case, we seem to be in agreement: carelessly (as opposed to carefully) written code can be immutable but not thread-safe. -- Jim Janney
From: Andreas Leitgeb on 18 Jul 2010 08:07 Jim Janney <jjanney(a)shell.xmission.com> wrote: > Andreas Leitgeb <avl(a)gamma.logic.tuwien.ac.at> writes: >> Jim Janney <jjanney(a)shell.xmission.com> wrote: >>> Peter Duniho <NpOeStPeAdM(a)NnOwSlPiAnMk.com> writes: >>>> I mean sure, there are ways that it could have been written >>>> incorrectly. The main (only?) non-thread-safe mistake being to use >>>> the "hash" field itself as the accumulator for the calculation. >>> public class SannyCode { >>> [ uses the "hash" field itself as the accumulator for the calculation.] >>> } >> That's the one sin which Pete already mentioned. > OK, here's a version that doesn't do that. > public class SannyCode { > private final String s; > private boolean calculated = false; > private long code = 0; > > public SannyCode(String s) { > this.s = s; > } > > public long getCode() { > if (!calculated) { > calculated = true; > long c = 0; > for (int i = s.length() - 1; i >= 0; i--) { > if (s.charAt(i) != '-') { > c += i; > } > } > code = c; > } > return code; > } > } > Still not thread-safe. Actually, I do think, this *is* thread-safe. You have to care for being more careless than that :-D > In any case, we seem to be in agreement: > carelessly (as opposed to carefully) written code can be > immutable but not thread-safe. And it's likely, that if one is *so* careless as to really make his immutable class thread-unsafe, that he will accidentally make it inadvertedly mutable as well ;-)
From: Andreas Leitgeb on 18 Jul 2010 08:25 Andreas Leitgeb <avl(a)gamma.logic.tuwien.ac.at> wrote: > Jim Janney <jjanney(a)shell.xmission.com> wrote: >> Andreas Leitgeb <avl(a)gamma.logic.tuwien.ac.at> writes: >>> Jim Janney <jjanney(a)shell.xmission.com> wrote: >>>> Peter Duniho <NpOeStPeAdM(a)NnOwSlPiAnMk.com> writes: >>>>> I mean sure, there are ways that it could have been written >>>>> incorrectly. The main (only?) non-thread-safe mistake being to use >>>>> the "hash" field itself as the accumulator for the calculation. >>>> public class SannyCode { >>>> [ uses the "hash" field itself as the accumulator for the calculation.] >>>> } >>> That's the one sin which Pete already mentioned. >> OK, here's a version that doesn't do that. >> public class SannyCode { >> private final String s; >> private boolean calculated = false; >> private long code = 0; >> >> public SannyCode(String s) { >> this.s = s; >> } >> >> public long getCode() { >> if (!calculated) { >> calculated = true; >> long c = 0; >> for (int i = s.length() - 1; i >= 0; i--) { >> if (s.charAt(i) != '-') { >> c += i; >> } >> } >> code = c; >> } >> return code; >> } >> } >> Still not thread-safe. > > Actually, I do think, this *is* thread-safe. I retract that. It *is* indeed thread unsafe. A second thread might reach the "if" exactly just after the first thread set calculated to true, and return 0 for the code. I "hate" myself, for missing that before ;)
From: Tom Anderson on 18 Jul 2010 08:27
On Sun, 18 Jul 2010, Andreas Leitgeb wrote: > Jim Janney <jjanney(a)shell.xmission.com> wrote: >> Andreas Leitgeb <avl(a)gamma.logic.tuwien.ac.at> writes: >>> Jim Janney <jjanney(a)shell.xmission.com> wrote: >>>> Peter Duniho <NpOeStPeAdM(a)NnOwSlPiAnMk.com> writes: >>>>> I mean sure, there are ways that it could have been written >>>>> incorrectly. The main (only?) non-thread-safe mistake being to use >>>>> the "hash" field itself as the accumulator for the calculation. >>>> public class SannyCode { >>>> [ uses the "hash" field itself as the accumulator for the calculation.] >>>> } >>> That's the one sin which Pete already mentioned. >> OK, here's a version that doesn't do that. >> public class SannyCode { >> private final String s; >> private boolean calculated = false; >> private long code = 0; >> >> public SannyCode(String s) { >> this.s = s; >> } >> >> public long getCode() { >> if (!calculated) { >> calculated = true; >> long c = 0; >> for (int i = s.length() - 1; i >= 0; i--) { >> if (s.charAt(i) != '-') { >> c += i; >> } >> } >> code = c; >> } >> return code; >> } >> } >> Still not thread-safe. > > Actually, I do think, this *is* thread-safe. Nope. Start with an instance where calculated = false and code = 0. Thread A turns up and starts executing getCode. It gets as far as 'long c = 0', at which point it ends its timeslice. For some reason, its writes are flushed to memory. calculated is now true, and code is still 0. Thread B turns up and starts executing getCode. It sees calculated is true, so skips over the if block, and returns the currents contents of code, which is 0. Failure has occurred. In fact, it's worse than that. Thread A could finish the method and update both calculated and code, but because there is no happens-before relationship between thread A and thread B, it's possible that B could come along later, and see the updated calculated but *not* the updated code. So even without an unlucky timeslice end, there is no guarantee of safety here. To make this method safe, you either have to synchronize the whole thing, or do the update of calculated and code atomically at the end. You could do the updates together in a synchronized block, but i think you might then also need to put any reads of them in synchronized blocks too. The alternative would be a volatile or atomic variable that holds an object containing both calculated and code, i think. The beauty of the String approach, of using a special value of code to indicate that it had not been calculated, is that you don't need any synchronisation for safety, just the JLS's guarantee of no word tearing in writes and reads of int variables. Because it combines the flag and value fields in a single int, they are read and written atomically as a pair. Of course, were you to do this, you might want to avoid String's ability to generate a code which looks like a flag indicating the lack of a code (ie 0). But then, you might think the one in four billion chance of it happening was insignificant. tom -- Suddenly, everything is clear ... |