Understanding the use of WeakHashMap as a cache

WeakHashMap uses WeakReference for its keys. In order for an entry to be kept in such a map, the key object of the entry needs to be referenced somewhere outside of the map; otherwise, the entry is removed in the next garbage collection, according to the definition of WeakReference.

Anonymous classes and garbage collection

If an anonymous class instance is not going to reference the implicit this to its enclosing instance, which is actually the majority of the uses where we are just too lazy to define another class, the anonymous class instance needs to be created from a static context, such as a static factory method. Otherwise, there is highly likely a memory leak.

Notes on Double-Checked Locking and 32-bit primitive values

To lazily initialize a variable of a reference type in a multithreaded environment, we either use the Initialization-On-Demand Holder or use the Double-Checked Locking with the variable being qualified by the volatile keyword. The variable does not need to be qualified by volatile if it is a 32-bit primitive such as int and float.

Restriction on shadowing variables

The Java Language Specification 3.0 §14.4.2 defines a restriction on variable shadowing to help detect bugs.

Java Compiler API and Maven integration

Suppose that we need to make some changes to our source code during a Maven build, e.g., we want to add a special method to a class for a testing Maven profile, but not for other Maven profiles. This post shows a method to achieve this by calling the Java Compiler API from a Maven plugin. The method does not require the knowledge of annotation processing or bytecode manipulation.

Find all the words in a list that are next to a given word

There is a list of four-letter words, such as aahs, aals, abas, abba, etc. Given an arbitrary four-letter word, find all the words in the list that are next to the given word, i.e., words that can be the same as the given word with exactly one letter changed. Example: given puma, the result could be duma, pima, puja, pula, pump, puna, pupa.

Queue latency benchmark: the Disruptor style vs the ArrayBlockingQueue style

Queue latency is the main performance metric that Disruptor sets itself apart from traditional queue implementations, e.g., ArrayBlockingQueue. To my understanding, Disruptor is based on volatile variable polling, rather than the blocking wait() and notify() mechanism. In this post, we benchmark the Disruptor polling style and the ArryaBlockingQueue blocking style using a simple queue with just one producer and one consumer. We define two latency metrics: one is the latency between a producer starts producing an item and ends producing the item, i.e., the producing latency; the other is the latency between a producer starts producing an item and a consumer starts consuming the same item, i.e., the queue latency. By definition, the queue latency includes the producing latency.

Sharing the internals among distinct immutable objects

Immutable objects have many advantages, e.g., they can be shared, and the sharing is thread-safe and can help avoid creating unnecessary objects. The only real disadvantage of making objects immutable is that a separate object is needed for each distinct value. This seems to be a big overhead for large immutable objects, but it is not always true. In some cases, the immutability can actually lead to a cheaper implementation than you would otherwise. The idea is that a distinct value is often not a completely different value. It is possible that some internals within immutable objects which themselves are immutable can be shared.

Reading Design Patterns by Erich Gamma et al., Addison-Wesley (1994)

Capturing a wealth of experience about the design of object-oriented software, four top-notch designers present a catalog of simple and succinct solutions to commonly occurring design problems. Previously undocumented, these 23 patterns allow designers to create more flexible, elegant, and ultimately reusable designs without having to rediscover the design solutions themselves. The authors begin by describing what patterns are and how they can help you design object-oriented software...

Reading Java Concurrency in Practice by Brian Goetz et al., Addison-Wesley (2006)

Threads are a fundamental part of the Java platform. Java SE 5 and 6 are a huge step forward for the development of concurrent applications, with improvements to the Java Virtual Machine to support high-performance, highly scalable concurrent classes and a rich set of new concurrency building blocks. In Java Concurrency in Practice, the creators of these new facilities explain not only how they work and how to use them, but also the motivation and design patterns behind them.