Multithreaded Programming ‘Can double-checked locking be fixed?’ Brian Goetz Finally, a fix for DCL! But how does it perform?BrianHere is the correct double-checked locking (DCL) for Java: class Singleton { private static Singleton theInstance; private static final ThreadLocal perThreadInstance = new ThreadLocal() { public Object initialValue() { return createInstance(); } }; public static Singleton getInstance() { // First check -- inside ThreadLocal.get() return (Singleton)perThreadInstance.get(); } private static synchronized Singleton createInstance() { // Double check if (theInstance == null) theInstance = new Singleton(); return theInstance; } } Please see https://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html#ThreadLocal for more information.AlexanderAlexander, I was expecting to hear from you on this subject. I too discovered this technique a while ago and recently saw the update on Bill Pugh’s Java Memory Model page discussing it and crediting you as the source. However, in my testing (Sun or IBM JDK 1.3 on a two-processor Linux/Intel box), I found that ThreadLocal.get() was measurably slower than an uncontended synchronize, and Doug Lea’s book (Concurrent Programming in Java, Second Edition, (Addison-Wesley, 1999; ISBN: 0201310090)) says the same. For that reason, I refrained from mentioning it in my article as a fix; while it solves the safety problem, it doesn’t deliver the performance benefit that DCL was supposed to deliver. In fact, under many conditions, it’s worse. Lea’s data shows that ThreadLocal is indeed faster under contended access, and the more heavily contended, the better it performs by comparison. But for uncontended access, it’s still slower. ThreadLocal.get() is just slow. Doug says it will be significantly faster in 1.4. Below is a test program I used to test the comparative performance of contended or uncontended access with synchronization, with ThreadLocal , and with nothing (unsafe access): TlTest.java, Timer.java import java.util.*; public class TlTest { static class Singleton { private static Object o; public static synchronized Object getSomething() { if (o == null) o = new Object(); return o; } } static class NSingleton { private static Object o; public static Object getSomething() { if (o == null) o = new Object(); return o; } } static class TlSingleton { private static ThreadLocal tl = new ThreadLocal(); public static Object getSomething() { Object o = tl.get(); if (o == null) { synchronized (TlSingleton.class) { o = Singleton.getSomething(); } tl.set(o); } return o; } } static int iterations=200000; static int nThreads = 5; static class SThread extends Thread { public void run() { for (int i=0; i<iterations; i++) { Object o = Singleton.getSomething(); } } } static class TThread extends Thread { public void run() { for (int i=0; i<iterations; i++) { Object o = TlSingleton.getSomething(); } } } static class NThread extends Thread { public void run() { for (int i=0; i<iterations; i++) { Object o = NSingleton.getSomething(); } } } public static void main(String[] args) throws Exception { Timer t = new Timer(); if (args.length >= 2) nThreads = Integer.parseInt(args[1]); if (args.length >= 3) iterations = Integer.parseInt(args[2]); Thread threads[] = new Thread[nThreads]; for (int i=0; i<nThreads; i++) { if (args[0].equals("S")) threads[i] = new SThread(); else if (args[0].equals("N")) threads[i] = new NThread(); else if (args[0].equals("T")) threads[i] = new TThread(); } t.start(); for (int i=0; i<nThreads; i++) threads[i].start(); for (int i=0; i<nThreads; i++) threads[i].join(); t.stop(); double sec = t.getTime() / 1000.0; System.out.println("Total time: " + sec + "s" + " (" + nThreads + " threads, " + iterations + " iterations)"); } } public class Timer { long startTime, endTime, lastPauseTime, totalPauseTime; boolean running = false, paused = false; public Timer() { } public void start() { startTime = System.currentTimeMillis(); running = true; } public void stop() { endTime = System.currentTimeMillis(); running = false; } public void pause() { lastPauseTime = System.currentTimeMillis(); paused = true; } public void resume() { if (paused) { long now = System.currentTimeMillis(); totalPauseTime += (now-lastPauseTime); paused = false; }; } public long getTime() { if (running) return System.currentTimeMillis() - startTime - totalPauseTime; else return endTime - startTime - totalPauseTime; } } Invoke it as: TlTest {S|N|T} <nThreads> <nIterations> Using nThreads=1 shows the cost of uncontended synchronization. The performance difference between nThreads=1 and nThreads=2 is enough that if there is any significant amount of contention, ThreadLocal starts to win out. ThreadLocal is a sensible technique to use and a useful addition to the class library (albeit poorly implemented) that doesn’t get enough attention. Brian GoetzJava Theory Encapsulation is not information hiding’ Wm. Paul RogersAuthors hash out information hidingWm. Paul, You, Jeff Mather [author of “Java Tip 107: Maximize Your Code Reusability,” (JavaWorld)], and Allen Holub [author of “Building User Interfaces for Object-Oriented Systems, Part 1,” (JavaWorld, July 1999)] really need to get together and hash all of this out. Three different authors, three different perspectives, all on JavaWorld. I would love to see an article that possibly resolves these perspectives (hint!): Your article: the more typical approach to information hiding/encapsulationMather’s article: the less conventional approach — split stateless methods into static methods in sister class to decouple from instances, which aids inheritanceHolub’s article: get and set methods are an evil excuse for encapsulation (pardon the loose paraphrase)A more specific comment: You change Route to retrieve Position object by index using (effectively) a clone, which is a change from returning an array. Wouldn’t it be better to return an Iterator of cloned Positions? That way, it is easy to convert the internal representation (array, ArrayList, or Vector) into a highly recognizable idiom for working with a list of items. Clark[Note: Allen Holub’s responses are in red, Wm. Paul Roger’s are in green, and Jeff Mather’s are in blue.]Clark et al., I suppose there’s room for discussion here, but I find Jeff’s notions of making classes all Booch utilities to be abhorrent (or at least not object-oriented). I’ve no argument with the idea that you should use interfaces as much as possible, but if the methods are stand-alone, then you simply don’t have an object system anymore, you have a bunch of global methods. The real debate, I suppose, is whether objects are good or not — and I come down on the side of objects. But don’t think that you have an object-oriented system if you have nothing but stateless objects calling static methods — that’s just an inconvenient way to write a procedural program. On the other hand, I think that Wm. Paul’s article is quite sound, though as you point out, I’d take it a step further and eliminate the get/set methods — you don’t actually need them. Generally, get/set methods appear in classes designed out of context. That is, if you design a dynamic model based on use-case analysis and then implement only those methods required by the dynamic model, you tend to not have much in the way of get/set methods. The get/set methods appear when you don’t know exactly how a class might be used, so you throw them in to make them more generic. Allen HolubClark, The perspective of information hiding in my article aligns closely with Allen’s articles. In particular, I think each of our articles emphasizes information hiding as a design principle. Allen does boldly state that getter/setter methods are evil, but I understand that to mean that those methods indicate that a class probably has been designed outside a specific domain problem. I have no objection to that notion. Rebecca Wirfs-Brock and Brian Wilderson discuss a fundamental principle driving design decisions in “Object-Oriented Design: A Responsibility-Driven Approach” (SIGPLAN Notices, Vol. 24, No. 10, October 1989): responsibility-driven design specifies object behavior rather than object structure. Also, I think Allen’s argument against getter/setter methods is that a class designed for a specific domain will often not need them. That falls in line with my statement that a class should encapsulate no more or less than a comprehensive set of reasonable responsibilities. What is reasonable? Let the domain be the guide! Is it reasonable that there will not be getter/setter methods? Absolutely. I readily admit that the class development in my article is not firmly grounded in a specific domain problem, and Allen points out that this often leads to generic solutions that include those rascally getter/setter methods. My article does not align well with Jeff’s. I don’t feel the procedural makeup of his methods are either necessary or advantageous. I specifically (though briefly) address the semantic advantage of currying a procedural-style function into an object-oriented call. And it seems to me that passing object references into globally visible static methods misses the power of polymorphism. Finally, addressing your “more specific comment.” Note that I did indicate the use of a copy constructor rather than a specific clone. You’ve kindly called this “effectively a clone.” It was actually a slip on my part. As I mentioned in the article, class Route is far from complete. I suspect when the actual responsibilities of Route are closely examined, an iterator over the Position objects would be likely, and a method directly accessing Position objects by index probably would not be warranted. Wm. Paul RogersGentlemen,I’m glad to see that there is consensus on the get/set issue. I will say that many of the developers I know do not accept this principle — for better or for worse. I once trotted out Allen’s series of articles that covered it. The principle was rejected as just an extreme view — as opposed to treating the principle as an ideal to strive towards. Personally, I can see the value but am not sure how to achieve it. Maybe it would be a good topic for a future article from Wm. Paul giving his spin on it in alignment with Allen’s previous series.Thanks for your interest,ClarkClark et al., The best way that I know to eliminate the get/set methods is to go through the design process, rather than throw together classes in an ad-hoc way. That is, start out with English problem statements, do use-case analysis, develop a dynamic model from the workflow in the use case, then (as the last step) capture the structure of the objects into a static model. Most programmers start with the static model, which is really working in the dark since you are just guessing about how the objects will be used. I’m in the middle of a series on the design process for IBM developerWorks, and you might want to read through that it. It’s indexed at https://www.holub.com/aiharticles.html. Allen HolubClark, I think the techniques presented in my article are complementary with those presented in Wm. Paul’s. I agree with “Place data and the operations that perform on that data in the same class,” but I would advise that you move the bulk of the code within those operations out to globally visible static methods to make that code easier to reuse. Doing so also tends to clean up the code to some degree, and makes it easier to debug since its total I/O interface is far easier to ascertain. I wish I had mentioned what Wm. Paul said under “Information hiding rule 3: Don’t expose a class’s internal structure” in my Java Tip, because it is a concrete application of my article’s Step 3, which I use all the time to enable reuse. I don’t subscribe to Allen’s prohibition on the use of getter and setter methods. What he’s essentially saying is that objects shouldn’t share information, which is contrary to what goes on in the real world, which objects are supposed to model. Only one object should be responsible for maintaining the value of any particular piece of data, but clients should be allowed to know that value where appropriate. Trying to design Allen’s way takes defensive programming to an extreme where it is a giant headache to get anything meaningful done. JeffClark et al., I don’t say, “Don’t share information.” Rather, the flow of information through the system should be minimized by carefully analyzing what the methods do, and that when information does flow, that it be encapsulated into objects that reify abstract (domain-level) classes. It’s always better to ask the object that has the data to do the work than to pass around the data so that the work can be done externally. Moreover, abstractions should only exist when they need to. For example, if several classes in the system embodied a domain-level concept of a Name, then it might make sense for a Name class to exist and for that class’s objects to be passed around. If only one class had a name, it would be much better for that class to have a do-something-with-your-name method. In no case would it be a good idea to pass a string around. It’s a basic precept of object-oriented programming that you don’t expose implementation details of that sort. Allen HolubClient-Side Java ‘Savor success with Java on the front end’ Alex KalinovskyInvasion of the giant appletsAlex,I enjoyed your article very much — it confirms much of what my team has been thinking. But you didn’t mention one problem staring us in the face: Our page designs tend to be rather large and have dynamic pieces embedded within static HTML-appropriate pieces. We needed some communication between the two and were chagrined to discover that Netscape 6 doesn’t support LiveConnect. We seemed forced to build the pages as giant applets that cover the entire page, not just to support the dynamic parts. Agree?Bill BrownBill, Unfortunately, I have to agree with you. It seems that the little effort that has been put into bridging Java applets and the HTML pages in which they reside has not evolved any further. In my experience we usually kicked off Java frames from the page, or as you mentioned, let applets cover most of the page. That’s not always a problem, but I certainly wish we had a better interface between Java apps and HTML documents. JavaScript has all these features, but I’m not a big fan of it. Alex KalinovskyJ2EE Project Management ‘J2EE project dangers!’ Humphrey SheilIs not deploying where you develop a significant danger?Humphrey,I’m sure you have received comments on Danger 4 “Not deploying where you develop.” This of course depends on how you develop. I develop primarily with Tomcat on NT and port to iPlanet on Solaris. I won’t go into the reasons why I do it this way. The build process uses Ant, I go by the Java 2 Platform, Enterprise Edition (J2EE) specifications, and life is wonderful. Or is it? Yes, there is an issue with deployment because of iPlanet quirks with J2EE, which is true for every vendor. I assume you were implying that the J2EE quirks are the issue, for example, how connection pooling is handled in each Enterprise JavaBean (EJB) container. Issues with the JVM versions are true for any development environment, J2EE or not.Regarding “Danger 7: Not designing for scalability or performance”: This seems like an object-oriented abstraction issue. Has the problem properly been abstracted? Can I make changes to a section of code or EJB for scalability?Regarding “Danger 8: Antiquated development processes”: I think this should be the Number 1 concern. Rapid application development (RAD) is about having proper processes. Forget Java, J2EE, and everything else, if you don’t have processes, you don’t have much.Proper build and testing is great, but code review catches more bugs.MalcolmMalcolm, You raise three points that I will address in turn: Deploying where you develop:I’ve seen this over and over again. Why develop somewhere else than you deploy? It introduces a higher risk than getting caught between different vendor implementations. The question to ask is: Why do I need to develop on an application server that isn’t where I deploy?Not designing for scalability or performance: I don’t mind where the issue falls into. It’s a serious danger in EJB design and development.Antiquated development processes: I see your concern here, however, I’ve seen too many green teams run headlong into disaster on J2EE projects, confident that the latest whizz-bang IDE or app server could save the day. They didn’t even get as far as having an antiquated development process.Humphrey SheilJava Beginner ‘Make cents with BigDecimal’ Robert NielsenWhat’s the big deal about BigDecimal?Robert,I am currently working on a program that calculates interest rates for ATM transactions. I found your article on the BigDecimal class to be quite useful.I am still left with a question about my project. At the beginning of your article, you state “To be able to write Java programs that deal with finances, you need to know about the BigDecimal class and numeric formatting.” It would be nice to get an understanding of why this class is necessary. I expressed all of my program’s values as doubles and noticed a few problems with accuracy compared to the Excel spreadsheet from where I took the calculations. Can you point me to any online resources that explain why the BigDecimal class is needed and why double values are not appropriate in this situation?ScottScott, Your question is a good one. Basically, the use of doubles involves a loss of precision. For example, if you create a double equal to 2 or 2.1, it won’t be exactly equal to 2 or 2.1, but an amount very, very close to those values. Often, this does not cause any problems. However, with repeated calculations or large numbers (e.g., 16 digits), you can start to see inaccuracies. BigDecimal objects, on the other hand, can be made exactly equal to numbers such as 2 or 2.1. Calculations completed with BigDecimals aren’t subject to the same errors involving the inaccuracies of doubles. That said, this brings up a caveat concerning numeric formatting. Because the BigDecimal object is changed first to a double before it is formatted, very large numbers will be formatted inaccurately by NumericFormat, that is, the values will be incorrect. For me, the solution to the formatting problem is to create my own class to format a BigDecimal object string, or buy a commercial formatting package (assuming one exists). Robert Nielsen Software Development