ThreadLocal
There is a Map in ThreadLocal, which maintains a copy for each thread to ensure that the data in each thread is isolated. Let's look at a small program
public class ThreadLocalDemo { static Person p = new Person(); public static void main(String[] args) { new Thread(() -> { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(p.name); },"t1").start(); new Thread(() -> { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } p.name = "Mary"; },"t2").start(); } static class Person { public String name = "Jack"; } }
The printing result is Mary. In fact, the result I want is Jack. I don't want the change of variables in t2 thread to affect the result of p1 thread. Therefore, ThreadLocal is needed to isolate the thread
public class ThreadLocalDemo2 { static ThreadLocal<Person> t = new ThreadLocal<>(); public static void main(String[] args) { new Thread(() -> { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(t.get()); },"t1").start(); new Thread(() -> { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } Person person = new Person(); person.name = "Mary"; t.set(person); },"t2").start(); } static class Person { public String name = "Jack"; } }
The execution result of this code is null. If people who don't know it will be curious, it is clear that Mary is set in t2 below. Why t1 gets null is because ThreadLocal isolates the thread
- Usage scenario of ThreadLocal
Spring declarative transaction ensures that the data connection is the same connection
Strong citation
The instance created by the strong reference new keyword, or the object created by Class.newInstance(), is a strong reference. The strong reference will be recycled by the garbage collector only when the reference is set to null. The code is as follows
public class NormalReferenceDemo { public static void main(String[] args) throws IOException { M m = new M(); m = null; System.gc(); //DisableExplicitGC System.in.read(); } }
SoftReference
The soft reference will be recycled by the garbage collector only when the memory is not enough. The code is as follows
public class SoftReferenceDemo { public static void main(String[] args) { SoftReference<byte[]> m = new SoftReference<>(new byte[1024 * 1024 * 10]); //m = null; System.out.println(m.get()); System.gc(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(m.get()); //Allocate another array, and the heap will not fit. At this time, the system will garbage collect. First, recycle it once. If it is not enough, it will kill the soft reference byte[] b = new byte[1024 * 1024 * 15]; System.out.println(m.get()); } }
WeakReference
The weak reference object pointed by the weak reference. If there is a strong reference to the reference object, once the strong reference is not available, the object will be recycled immediately when garbage collection. Use the scene "container" (ThreadLocal source code). The weak reference is simple to use the code
public class WeakReferenceDemo { public static void main(String[] args) { WeakReference<M> m = new WeakReference<>(new M()); System.out.println(m.get()); System.gc(); System.out.println(m.get()); ThreadLocal<M> tl = new ThreadLocal<>(); tl.set(new M()); tl.remove(); } }
This is how the ThreadLocal is executed internally, as shown in the following figure
Virtual reference
- Virtual reference management out of heap memory
Easy to use code
public class PhantomReferenceDemo { private static final List<Object> LIST = new LinkedList<>(); private static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>(); public static void main(String[] args) { PhantomReference<M> phantomReference = new PhantomReference<>(new M(), QUEUE); new Thread(() -> { while (true) { LIST.add(new byte[1024 * 1024]); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } System.out.println(phantomReference.get()); } }).start(); new Thread(() -> { while (true) { Reference<? extends M> poll = QUEUE.poll(); if (poll != null) { System.out.println("--- Virtual reference objects are jvm Recovered ---- " + poll); } } }).start(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } }
The execution result is shown in the figure:
We found that the fetching is null, because the virtual reference will be loaded into the Queue when it is recycled, but we can't get the object that the virtual reference points to by ourselves, because this memory doesn't belong to the heap memory in the JVM, but directly opens up the out of heap memory. We can't get the object in the out of heap memory through java. See the following figure