Skip to main content

Posts

Showing posts from 2008

Date-Race-Ful Lazy Initialization for Performance

I was asked a question about benign data races in Java this week, so I thought I would take the opportunity to discuss one of the (only) approved patterns for benign races. So, at the risk of encouraging bad behavior (don't use data races in your code!), I will discuss the canonical example of "benign races for performance improvement". Also, I'll put in another plug for Josh Bloch's new revision of Effective Java (lgt amazon) , which I continue to recommend. As a reminder, basically, a data race is when you have one (or more) writes, and potentially some reads; they are all to the same memory location; they can happen at the same time; and that there is nothing in the program to prevent it. This is different from a race condition , which is when you just don't know the order in which two actions are going to occur. I've put more discussion of what a data race actually is at the bottom of this post. A lot of people think that it is okay to have a data

What Volatile Means in Java

Today, I'm going to talk about what volatile means in Java. I've sort-of covered this in other posts, such as my posting on the ++ operator , my post on double-checked locking and the like, but I've never really addressed it directly. First, you have to understand a little something about the Java memory model. I've struggled a bit over the years to explain it briefly and well. As of today, the best way I can think of to describe it is if you imagine it this way: Each thread in Java takes place in a separate memory space (this is clearly untrue, so bear with me on this one). You need to use special mechanisms to guarantee that communication happens between these threads, as you would on a message passing system. Memory writes that happen in one thread can "leak through" and be seen by another thread, but this is by no means guaranteed. Without explicit communication, you can't guarantee which writes get seen by other threads, or even the order in whic

G1 Garbage Collector in Latest OpenJDK Drop

ETA: The G1 collector is now in the latest JDK6 release, which you can download from Sun here . You can enable it for testing with the flags -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC . Original post follows. For those of you who are interested in tinkering with new garbage collectors, the "Garbage-first" G1 garbage collector is in the new JDK7 drop from OpenJDK . I haven't tried it yet, but I am looking forward to seeing what it does. (You will notice the link doesn't say anything about the new GC. Here's the appropriate bug .) G1 is supposed to provide a dramatic improvement on existing GCs. There was a rather good talk about it at this year's JavaOne. It allows the user to provide pause time goals, both in terms of actual seconds and in terms of percentage of runtime. The principle is simple: the collector splits the heap up into fixed-size regions and tracks the live data in those regions. It keeps a set of pointers — the "remembered set&

A Brief Digression into Politics

A plea for you to vote "No" on CA Proposition 8, and maintain the rights of same-sex couples in California. I really hate using this blog as a political forum. I have a personal blog I use for that, read only by people who know me. This blog should be expressly for computer-related topics. I apologize to readers expecting me to talk about concurrency or APIs or anything else. I apologize to readers who don't like to see discussion of this issue, or to those who have a problem with the way I handle it. Today's post is just for the California voters. On November 4th, we are going to be asked to vote on Proposition 8, which is only 14 words long: "Only marriage between a man and a woman is valid or recognized in California." Please vote no on this proposition, and keep California safe for families of all kinds. A lot of you might wonder why a heterosexual who only blogs about software engineering and computer science might feel compelled to write about t

Don't Use StringBuffer!

One thing I have noticed among Java API users is that some don't seem to know that there is a difference between StringBuffer and StringBuilder. There is: StringBuffer is synchronized, and StringBuilder isn't. (The same is true for Vector and ArrayList, as well as Hashtable and HashMap). StringBuilder avoids extra locking operations, and therefore you should use it where possible. That's not the meat of this post, though. Among those who know that StringBuffer is synchronized, they sometimes think that it has magical thread-safety properties. Here's a simplified version of some code I wrote recently final StringBuilder sb = new StringBuilder(); Runnable runner = new Runnable() { @Override public void run() { sb.append("1"); } }; Thread t = new Thread(runner); t.start(); try { t.join() } catch (InterruptedException e) {} // use sb. A fellow looked at this code, and said that he thought I should use StringBuffer, because it is safer with multiple th

Top 3 Reasons Why Constructors are Worthless

In my last post, I made an offhand reference to the fact that object constructors are worthless in Java. I was asked why this is, so I thought I'd fill in the details. This topic is a little more well-understood by the developer community than some of the concurrency tidbits that I usually discuss. People who use dependency injection toolkits like Guice and Spring 's inversion of control tend to have very strong feelings on the advanced suckitude of constructors. I know quite a few developers who claim that use of Guice changed the way they code (for the better). ETA: I've had a few people tell me just to use SPI. The point of this post is not that DI is wonderful, it is that constructors are awful. SPI doesn't stop constructors from being awful. In fact, it is yet another horrible solution, what with all of those Foo and FooImpl classes. If you like SPI, go ahead and use it. Furthermore, neither DI nor SPI addresses two of the three issues I mentioned. So, wi

Immutability in Java, Part 3: Deserialization and Reflection

This time, I'll talk about deserialization, immutability and final fields. I'll try to be a little shorter. I spent the last two posts on immutability ( here and here ) talking about what it takes to make an object's fields immutable. This advice mostly boiled down to "it has to be final and set before the constructor ends". When you have deserialization, though, the fields can't be set before the constructor ends. An instance object is constructed using the default constructor for the object, and the fields have to be filled in later. We gave deserialization special semantics, so that when an object was constructed this way, it would behave as if it had been constructed by an ordinary constructor. No problems there. The problems come when and if you need to write custom deserialization (using, for example, the readObject method of ObjectInputStream ). You can do this using reflection: Class cl = // get the class instance Field f = cl.getDeclaredFiel

Immutability in Java, Part 2

I'd like to talk a little more about what it takes to ensure thread-safe immutability in Java, following on from a (semi)recent post I made on the subject. The basic gist of that post was that if you make data immutable, then they can be shared between threads without additional synchronization. I call this "thread-safe immutability". In that post, I said this: Now, in common parlance, immutability means "does not change". Immutability doesn't mean "does not change" in Java. It means "is transitively reachable from a final field, has not changed since the final field was set, and a reference to the object containing the final field did not escape the constructor". I just wanted to go over these points again, because I get a lot of questions about them and there are a couple of things I glossed over. Let's take them one by one. Immutability means... the object is transitively reachable from a final field What this means is that y

Double Checked Locking

I still get a lot of questions about whether double-checked locking works in Java, and I should probably post something to clear it up. And I'll plug Josh Bloch's new book, too. Double Checked Locking is this idiom: // Broken -- Do Not Use! class Foo {   private Helper helper = null;   public Helper getHelper() {     if (helper == null) {       synchronized(this) {         if (helper == null) {           helper = new Helper();         }       }     }   return helper; } The point of this code is to avoid synchronization when the object has already been constructed. This code doesn't work in Java. The basic principle is that compiler transformations (this includes the JIT, which is the optimizer that the JVM uses) can change the code around so that the code in the Helper constructor occurs after the write to the helper variable. If it does this, then after the constructing thread writes to helper, but before it actually finishes constructing the object,

Which Lock is Which?

I was at JavaOne last week, and attended Bill Pugh's Defective Java talk. Bill had an important point about what kind of locks you want to be using and what kind you don't, and that point is worth repeating. Bill is, with Dave Hovemeyer, the guy behind FindBugs , which everyone should be using religiously. He was also my graduate advisor; we worked together on the new Java Memory Model. If there are two things Bill knows, they are concurrency and bug patterns. There is a tremendously useful defensive locking discipline that I use all of the time, and recommend that other people use, too: class Foo { private final Object lock = new Object(); private Bar lockProtectsMe; ... public void blah() { synchronized (lock) { // accesses LockProtectsMe... ... } } } This has the following benefits: If you try to acquire the lock on the Foo object instead of the lock, you run the risk that some code outside the class obtains that lock. Perhaps forever . Usi

Immutability in Java

Another topic that comes up again and again in questions that people ask me is, "How does immutability work in Java"? Immutability is a godsend for concurrent programmers, because you don't have to do lots of sticky reasoning about what threads are updating what variables when, and you don't have to worry about cache thrashing, and you don't have to worry about all sorts of things. When I write concurrent code (which is reasonably often), I try to make as many things immutable as possible. Now, in common parlance, immutability means "does not change". Immutability doesn't mean "does not change" in Java. It means "is transitively reachable from a final field, has not changed since the final field was set, and a reference to the object containing the final field did not escape the constructor". In circumstances other than this, even if a given field is not mutated, the Java memory model requires that there be some form of synchr

Java Performance Talk

Paul Tyma and I gave a talk at SD West today on Java Performance Myths. The big takeaway was this: Most of the things you think you know about Java performance are really hard to quantify. Write the best code you can. Profile it to find the bottlenecks. Remove the bottlenecks. Rinse and repeat. A couple of other takeaway points here: Don't forget to upgrade every so often. JDK6, for example, runs code compiled for JDK4 just fine, and you get a big performance boost. For free. Memory allocation is pretty cheap. Know that there are three garbage collectors, and know which one is best, when. Read the Java memory management white paper . Hotspot can do lots of things to optimize your locks, but it often doesn't. Having said that, the bottlenecks in concurrent code usually have to do with contention, not synchronization overhead. Use low contention data structures like ConcurrentHashMap to avoid contention, but don't try to get clever with locking. Contrary to popu

Causality and the Java Memory Model

NB: I started writing this last August, and sent it to a friend of mine for thoughts. I just realized that he never got back to me on it, and I never posted it. I don't much feel like editing it now, so here it is in its original glory Okay, I know. It is nearly impossible to read and understand the causality bits of the Java memory model. That's all that stuff about "Executions and Causality Requirements" on pages 568 – 570 of the Java Language Specification . Bill Pugh, Sarita Adve and I wrote it. Basically, in the last three years, there have been three kinds of reactions to it: ZOMGWTF!? (I'm a normal human being. Give me a break.) This is incomprehensible gibberish. (I'm a pretty smart cookie and I think that everything I can't understand in three seconds is worthless.) Okay, I think I get it, but I have some questions. (I'm a pretty smart cookie and I spent several days trying to understand it.) I find that the last group usually prett