preface
In concurrent programming, in addition to maintaining and modifying shared variables, sometimes we also need to set a private variable for each thread to carry out thread isolation. The ThreadLocal provided by Java can help us achieve this, and when talking about ThreadLocal, we have to talk about the four kinds of References in Java. Different Reference types behave differently during GC. Reference types help us understand how to quickly reclaim memory of certain objects or GC control of an instance
- Four reference types are available during the lifetime of the JVM
- ReferenceQueue (ReferenceQueue)
- Implementation principles and usage of ThreadLocal
- The implementation principle of FinalReference and Finalize methods
- Cheaner mechanism
Pay attention to the public account, communicate together, wechat search: sneak forward
Four reference types in the lifetime of the JVM
Strong reference (StrongReference)
- An object is created and assigned to a reference variable. A strong reference to a reference variable is never garbage collected. The JVM would rather throw an OutOfMemory exception than reclaim the object. Creation of strong reference objects, such as
Integer index = new Integer(1);
String name = "csc";
Copy the code
- If you break all references to a strongly referenced object (assign the reference variable to null), the JVM will reclaim the object at the appropriate time
Soft references (SoftReference)
- It differs from strong references in that when memory runs out, this type of reference object is collected by the garbage processor
- Using soft references prevents memory leaks and makes your program more robust. One instance of SoftReference holds a SoftReference to a Java object, and the existence of the SoftReference does not prevent the garbage collection thread from collecting the Java object
- The get() method provided by the SoftReference class returns a strong reference to a Java object. In addition, once the garbage thread has reclaimed the object, the get() method returns NULL
String name = "csc";
// Create a soft reference
SoftReference<String> softRef = new SoftReference<String>(name);
System.out.println(softRef.get());
Copy the code
A weak reference (WeakReference)
- Features: Regardless of whether there is sufficient memory, whenever GC is performed, it will be reclaimed
static class User{
String name;
public User(String name){ this.name = name; }
public String getName(a) { return name; }
public void setName(String name) { this.name = name; }}// Create a weak reference
WeakReference<User> softRef = new WeakReference<User>(new User("csc"));
System.out.println(softRef.get().getName()); / / output CSC
System.gc();
System.out.println(softRef.get()); / / output is null
// Weak reference Map
WeakHashMap<String, String> map = new WeakHashMap<String, String>();
Copy the code
Phantom reference (PhantomReference)
- Features: as imaginary, and no reference no difference; Unlike soft and weak references, virtual references do not determine the life cycle of an object. If an object is associated with a virtual reference, it can be collected by the garbage collector at any time, just as if no reference was associated with it
- Note that the virtual reference must be associated with the reference queue. When the garbage collector attempts to reclaim an object and finds that it has a virtual reference, it adds the virtual reference to the reference queue associated with it. A program can determine whether a referenced object is about to be garbage collected by determining whether a virtual reference has been added to the reference queue
public static void main(String[] args) {
ReferenceQueue<User> queue = new ReferenceQueue<>();
PhantomReference<User> pr = new PhantomReference<User>(new User("csc"), queue);
//PhantomRefrence's get method always returns NULL, so the corresponding reference object cannot be accessed.
System.out.println(pr.get()); // null
System.gc();
System.out.println(queue.poll()); // Get the ReferenceQueue of the garbage collected "XB"
}
Copy the code
Reference types | Time to be garbage collected | scenario | Time to live |
---|---|---|---|
Strong reference | never | The general state of the object | Terminates when the JVM stops running |
Soft references | When memory is low | Object caching | Terminates when out of memory |
A weak reference | Normal garbage collection | Object caching | Garbage collection terminates |
Phantom reference | Normal garbage collection | Track the garbage collection of objects | Garbage collection terminates |
2 ReferenceQueue (ReferenceQueue)
- Reference queues can be used with soft references, weak references and virtual references. When referenced objects are about to be reclaimed by the JVM, they are added to the reference queue
ReferenceQueue<String> queue = new ReferenceQueue<String>();
WeakReference<String> pr = new WeakReference<String>("wxj", queue);
System.gc();
System.out.println(queue.poll().get()); // Get the string WXJ to be reclaimed
Copy the code
3 Principles and usage of ThreadLocal
How ThreadLocal works
- Each thread has a built-in ThreadLocalMap object
public class Thread implements Runnable {
/* The current thread uses ThreadLocal
as the Key and * T as the value */ for the ThreadLocalMap instance
ThreadLocal.ThreadLocalMap threadLocals = null;
Copy the code
- As an internal class of ThreadLocal, ThreadLocalMap realizes functions similar to HashMap. Its element Entry is inherited from WeakReference, key value is ThreadLocal, and value is reference variable. This means that the VALUE object is reclaimed when the JVM GC occurs
public class ThreadLocal<T> {
// The hash value of the ThreadLocal object, implemented using a static AtomicInteger
private final int threadLocalHashCode = nextHashCode();
/ / set the value
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if(map ! =null)
map.set(this, value);
else
createMap(t, value);
}
/ / get the value
public T get(a) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if(map ! =null) {// Get the current thread's ThreadLocalMap, and then use the object ThreadLocal to get the corresponding value
ThreadLocalMap.Entry e = map.getEntry(this);
if(e ! =null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
returnresult; }}returnsetInitialValue(); }...// Class like HashMap
static class ThreadLocalMap {
// Use the open address method to resolve hash conflicts
// If the hash index already has a value, the algorithm looks for empty Spaces in the following positions
privateEntry[] table; .//Entry is weak reference
static class Entry extends WeakReference<ThreadLocal<? >>{
/** The value associated with this ThreadLocal. */Object value; Entry(ThreadLocal<? > k, Object v) {super(k); value = v; }}}Copy the code
ThreadLocal does not guarantee the safety of shared variables in multiple threads
- As can be seen from the implementation principle of ThreadLocal, ThreadLocal only stores one duplicate variable for each thread, and the modification of duplicate variable does not affect the variable value of other threads. Therefore, ThreadLocal cannot realize the security of shared variables
Usage scenarios of ThreadLocal
- Thread safety, wrapped thread unsafe tools, such as Java. Text. SimpleDateFormat classes, of course jdk1.8 has given the corresponding Java thread safe class. Time. The format. DateTimeFormatter
- Thread isolation, such as database connection management, Session management, MDC log tracking, and so on.
ThreadLocal memory leak and WeakReference
- Threadlocalmap. Entry is a weak reference, and a weak reference object is garbage collected whether or not it is referenced
- A memory leak occurs on a thread whose lifetime is long. The threadLocals reference will always exist. When the ThreadLocal is reclaimed, its Entity becomes an instance of LLDB ()==null. A memory leak occurs when the thread dies and the Entity is never reclaimed
- If threads operate on the same ThreadLocal across businesses, variable safety issues can also arise
- It is usually best to call remove() of a ThreadLocal when it is finished using it; When a ThreadLocal gets or sets a ThreadLocal, it is best to check whether the current Entity key is null. If null, the Entity is released and the value is garbage collected
4 FinalReference of Finalize method
final class Finalizer extends FinalReference<Object> {private static ReferenceQueue<Object> queue = new ReferenceQueue<>();
/* Invoked by VM */
static void register(Object finalizee) {
new Finalizer(finalizee);
}
private static class FinalizerThread extends Thread {...public void run(a) {...for (;;) {
try {
Finalizer f = (Finalizer)queue.remove();
// Call Object.finalize will be implemented heref.runFinalizer(jla); . }static{... Thread finalizer =newFinalizerThread(tg); .// Execute the daemon thread of Object.Finalize
finalizer.setDaemon(true);
finalizer.start();
}
Copy the code
- If CPU resources are scarce, FinalizerThread may delay the Finalize method of Finalizer due to its low priority
- As the Finalize method of Finalizer objects is not executed late, most finalizer objects may enter the old generation, which is easy to trigger gc of the old generation, or even FULLGC, and the gc pause time becomes significantly longer
5 Cheaner mechanism
- The last article introduced the jdk1.8 Cleaner framework: ByteBuffer and netty.ByteBuf details
Corrections are welcome
Refer to the article
- How ThreadLocal works and how it works
- JDK source code analysis FinalReference complete interpretation
- An optimization practice of Young GC
- Netty resource leak detection
- Avoid using Finalizers and Cleaner mechanisms
- 【JAVA Reference】Cleaner source code analysis (three)