-XX:+UseSerialGC
-client
.-XX:+UseParallelGC -XX:ParallelGCThreads=n
Old gen: use 1 thread. Don't compacts the space
-XX:+UseParallelOldGC
-XX:+UseConcMarkSweepGC -XX:ParallelCMSThreads=n
-XX:+UseG1GC
(Garbage First Collector java 7+)
For java 8u20: can use -XX:+UseStringDeduplication
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:
instance
fieldConsequence: 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?
instance
field (only true for jdk >= 1.5)Singleton
was created. ThreadLocal
(see the reference Double-Checked Locking is Broken" Declaration))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;
}
}
}
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)
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)!sleep
synchronized
blockThread
wait
synchronized
block synchronized (monObj) { ...
monObj.wait(1000);
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.
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....
}