Java core

Memory model

Java memory model

Garbage collectors

Java Garbage collectors

  • -XX:+UseSerialGC
    • Good for:
      • Client machine. Default if using -client.
      • Small CPU
      • App with small memory footprint
      • Machine running multiples JVM
      • Embedded hardware
  • -XX:+UseParallelGC -XX:ParallelGCThreads=n

    • Good for: Lot of work need to be done and long pauses are acceptable. For example:
      • Batch processing
      • Performing a large number of database queries
    • Young gen: use n (=CPU cores) threads
    • Old gen: use 1 thread. Don't compacts the space

    • -XX:+UseParallelOldGC
      • Young gen: use n (=CPU cores) threads.
      • Old gen: use n (=CPU cores) threads. Don't compacts the space
  • -XX:+UseConcMarkSweepGC -XX:ParallelCMSThreads=n

    • Good for: responsive applications where we can’t afford longer pause times:
      • desktop UI application that respond to events
      • a webserver responding to a request
      • a database responding to queries.
    • Young gen: same algorithm as parallel GC
    • Old gen: Don't compacts the space
  • -XX:+UseG1GC (Garbage First Collector java 7+) For java 8u20: can use -XX:+UseStringDeduplication
    • Good for:
      • Heap sizes >= 6GB
      • stable and predictable pause time < 0.5 seconds.
    • divides the heap space into multiple equal-sized regions.
    • the region with lesser live data will be collected first

Concurrency

Double-checked locking idiom

Short and sweet: DON'T use it. It's broken!

Why? Because while the writer thread has not yet finished initialized the instance, the reader thread may see a non-null instance but with default values in its attributes.

public class Singleton {
    private static Singleton instance;

    private Singleton() {     }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

Scenario: The Singleton object is created, then, its object reference would be written to the instance field BEFORE all attributes of the Singleton object is initialized (by the constructor).

More detail:

  • If the compiler can prove that the constructor cannot throw an exception or perform synchronization, it can freely reorder (which one happens before the other) the writes that initialize the object and the write to the instance field
  • Even if the compiler does not reorder those writes, this pattern is still broken on multiprocessors systems: the processors/memory system may reorder those writes.

Consequence: a thread which invokes getInstance() could see a non-null reference to a Singleton object, but instead of seeing a full initialized Singleton object, it could see the default values for fields of the Singleton object.

What is working safely?

  • Use double-check locking together with violate keyword on the instance field (only true for jdk >= 1.5)
  • Synchronize the entire factory method (yield unnecessary - and costly - synchronization after the Singleton was created.
  • Use Enum instead (but it will make difficult for unittest as enum cannot be mocked)
  • Statically create the instance field (yes, if the cost of having the singleton created is small, just do this)
  • Use a IoC container like Spring
  • Use ThreadLocal (see the reference Double-Checked Locking is Broken" Declaration))
  • If still need lazy initialization, use Bill Pugh's approach
public class Singleton {
    private Singleton() {     }

    private static class SingletonHelper {
        // this is threadsafe initialization
        private static final Singleton INSTANCE = new Singleton();

        public static Singleton getInstance() {
            // the SingletonHelper class will not be loaded until this         
            // method is called, thus the Singleton instance won't be         
            // be created until this time
            return SingletonHelper.INSTANCE;
        }
    }
}

Synchronized

Do not synchronize on non-final field as the the reference can change and the result is no synchronization at all!

Do not use String object as a lock! Reason: string literals are stored in string pool. If, by chance, another code (or 3rd-party libs) that uses the String object with the same literal, they will be synchronized together despite of the fact that they are completely unrelated!

Java's SimpleDateFormat is NOT thread-safe! Workaround: synchronize it before use; put an instance in ThreadLocal; use another utils (like commons-lang's FastDateFormat)

Volatile

Volatile solve

Ensure visibility: reads/writes are always from/to main memory instead of CPU cache/thread's cache (trade-off: slower), thus all threads can see the same value

Ensure automic: writes of 64-bit values (long, double...) will finish at a whole (some platforms write 32-bit chunks)

Ensure the happens-before relation: (applicable for >= java 5) reads that happens after a write will see the value when the write finishes.

Prevent seeing half-initialized object: (>= java 5) object reference will not be publish until initialized.

Prevent reordering: prevent unexpected behaviors caused by code-reordering of compiler

public class VolatileExample {
    private int x = 0;
    private volatile boolean v = false;
    public void writer() {
        // since java 5, it is guaranteed that "x = 42" will always be done before "v = true"      
        // before java 5, the compiler is freely reorder this.
        x = 42;
        v = true;
    }
    public void reader() {
        if (v == true) {
            print(x); // since java 5, always output 42.
        }
    }
}

Notes:

  • ++ or -- operations on volatile variable are NOT automic (as it comprises 2 operations: read the value, inc/dec then write. Only the write is automic)!
  • Double-locking idiom now works with violate

sleep, wait, notify, notifyAll

sleep

  • don't require a synchronized block
  • called on Thread
  • woken up by
    • timeout
    • interrupt

wait

  • must be called inside a synchronized block
  • called on the monitor object i.e.
  synchronized (monObj) { ... 
     monObj.wait(1000);
  • woken up by
    • timeout
    • notify / notifyAll (on the monitor object)

notify

one (don't know which one) of waiting threads get woken up. Generally used for resource pool

notifyAll

All waiting threads will be woken up. Generally used for all cases.

Thread pool

Parameters

Thread pool's parameters

ForkJoinPool

private static class SomeTask extends RecursiveTask<Boolean> {

    @Override
    protected Boolean compute() {
        if (is processing size) {
            return doCompute();
        }

        List<SomeTask> allTasks =
                Lists.partition(to processing size)
                     .stream()
                     .map(ids -> new SomeTask...)
                     .collect(Collectors.toList());

        return invokeAll(allTasks)
                .stream()
                .map(ForkJoinTask::join)
                .reduce((r1, r2) -> r1 && r2)
                .orElse(false);

        /*
           Don't do like following as it won't utilize all threads in pool

           SomeTask taskLeft = new SomeTask...
           taskLeft.fork();

           SomeTask taskRight = new SomeTask...
           taskRight.fork();

           boolean left = taskLeft.join();
           boolean right = taskRight.join();

           return left && right;
        */
    }

    private boolean doCompute....

}