This is the 30th day of my participation in the August Text Challenge.More challenges in August
AQS
Read the source code skills
- Can’t run not read;
- Purposeful;
- A clue to the end; Draw a method call diagram and understand its implementation. Draw a class diagram for the class
- Skip over irrelevant details;
- Generally do not read static, read dynamic method;
AbstractQuenedSynchronizer abstract queue type synchronizer, is apart from the Java own synchronized keyword locking mechanism. AQS called (AbstractQueuedSynchronizer), all the classes in Java. The util. Concurrent. The locks.
** Note: AQS are spinlocks: ** When waiting for wake up, spin is often used (while(! Cas ())) attempts to acquire the lock until it is successfully acquired by another thread
AQS locks are: spin lock, mutex lock, read lock write lock, conditional yield, semaphore, fence are derivatives of AQS
Design patterns
Template Method
The framework for processing processes is defined in the parent class and the specific processing methods are implemented in the child class
Callback Callback function
The Lock source
- Reentrantlock function call procedure
- A volatile int state variable is maintained in the AQS to indicate the current synchronization state. Each node in the bidirectional linked list is a thread.
/** * Link to predecessor node that current node/thread relies on * for checking waitStatus. Assigned during enqueuing, and nulled * out (for sake of GC) only upon dequeuing. Also, upon * cancellation of a predecessor, we short-circuit while * finding a non-cancelled one, which will always exist * because the head node is never cancelled: A node becomes * head only as a result of successful acquire. A * cancelled thread never succeeds in acquiring, and a thread only * cancels itself, not any other node. */
volatile Node prev;
/** * Link to the successor node that the current node/thread * unparks upon release. Assigned during enqueuing, adjusted * when bypassing cancelled predecessors, and nulled out (for * sake of GC) when dequeued. The enq operation does not * assign next field of a predecessor until after attachment, * so seeing a null next field does not necessarily mean that * node is at end of queue. However, if a next field appears * to be null, we can scan prev's from the tail to * double-check. The next field of cancelled nodes is set to * point to the node itself instead of null, to make life * easier for isOnSyncQueue. */
volatile Node next;
/** * The thread that enqueued this node. Initialized on * construction and nulled out after use. */
volatileThread thread; .../** * Head of the wait queue, lazily initialized. Except for * initialization, it is modified only via method setHead. Note: * If head exists, its waitStatus is guaranteed not to be * CANCELLED. */
private transient volatile Node head;
/** * Tail of the wait queue, lazily initialized. Modified only via * method enq to add new wait node. */
private transient volatile Node tail;
/** * The synchronization state. */
private volatile int state;
Copy the code
-
State is visible using volatile modifiers, and changing the value of state is implemented by compareAndSetState. The underlying implementation is the CAS operation. The AQS = CAS + voliate
-
VarHandle
A VarHandle is a reference to a variable, which was added after 1.9
Function: You can set variables directly through Handle. Its operation is atomic and operates directly on binary code. Making it easier to secure threads.
-
AQS defines two ways of resource sharing:
- Exclusive: Exclusive. Only one thread can execute this lock, such as ReentrantLock
- Share: a Share that can be executed simultaneously by multiple threads, such as Semaphore, CountDownLatch, ReadWriteLock, and CyclicBarrier
-
Unlock source (to be added) :
ThreadLocal
-
Threadlocal is an internal storage class that can store data in a specified thread. Once the data is stored, only the specified thread can get the stored data. If you look at this code, the output is null. Why is that?
//volatile static Person p = new Person(); static ThreadLocal<Person> tl = new ThreadLocal<>(); public static void main(String[] args) { new Thread(()->{ try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(tl.get()); }).start(); new Thread(()->{ try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } tl.set(new Person()); }).start(); } static class Person { String name = "zhangsan"; } Copy the code
-
First take a look at the internal implementation of ThreadLocal
Official note:
This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its {@code get} or {@code set} method) has its own, independently initialized copy of the variable. {@code ThreadLocal} instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID). Copy the code
This class provides thread-local variables. These variables are different from normal variables because each thread that accesses a thread (through its {@code get} or {@code set} methods) has its own, independently initialized copy of the variable. An instance of {@code ThreadLocal} is typically a private static field in a class that you want to associate state with a thread (for example, a user ID or transaction ID). (Google translated a wave)
The main thing you can see is the get/set method
Get method implementation
public T get(a) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if(map ! =null) { ThreadLocalMap.Entry e = map.getEntry(this); if(e ! =null) { @SuppressWarnings("unchecked") T result = (T)e.value; returnresult; }}return setInitialValue(); } Copy the code
The internal static ThreadLocalMap class maintains an Entry[] table for each thread, accessible only by the current thread, which explains why the values initialized by the external Person are not available in the current thread.
The get method
public T get(a) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if(map ! =null) { ThreadLocalMap.Entry e = map.getEntry(this); if(e ! =null) { @SuppressWarnings("unchecked") T result = (T)e.value; returnresult; }}return setInitialValue(); } Copy the code
Set method
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if(map ! =null) map.set(this, value); else createMap(t, value); } Copy the code
GetMap: ThreadLocal value associated with this thread. This map collection can only pass through this class
/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null; Copy the code
-
ThreadLocal a few other points to note
-
Thread has a map, ThreadLocalMap
-
The key of a ThreadLocalMap is ThreadLocal, and the value is our own.
-
ThreadLocal is a weak reference, and when null, it is garbage collected
-
ThreadLocalMap has the same lifecycle as Thread, and it will not be collected. If ThreadLocalMap has the same lifecycle, it will not be collected. The key of ThreadLocalMap is missing, but the value is still there, causing a memory leak.
Solution: After using ThreadLocal, run the remove operation to avoid memory overflow.
-
-
USES:
Declarative transactions guarantee the same Connection
-
Strong weak virtual reference
1. :
When running out of memory, the Java virtual machine would rather throw OutofMemoryErrors to abort the program than randomly recycle objects with strong references.
package com.anzhi.Reference;
import java.io.IOException;
public class StrongReference {
public static void main(String[] args) throws IOException{
// Strong references are the most commonly used references. If an object has a strong reference, the garbage collector will never collect it.
Object o = new Object();
// If you want to reclaim a strong reference type, you need to weaken it
o = null;
System.gc(); // Explicitly invoke garbage collection
System.in.read(); //GC is another thread, the main thread terminates, the thread also terminates, so the main thread blocks observation}}Copy the code
Note: But if the o is a global variable, you need to assign it to NULL when the object is not used, because strong references are not garbage collected.
2. Soft:
-
Caching of large objects;
-
Cache of commonly used objects;
-
If an object has only soft references, the garbage collector will not reclaim it when there is enough memory; If you run out of memory, the objects are reclaimed. As long as the garbage collector does not collect it, the object can be used by the program.
package com.anzhi.Reference; import com.anzhi.ThreadMessage.ThreadMessage; import java.lang.ref.SoftReference; /* * If an object has only soft references, the garbage collector will not reclaim it when there is enough memory; * If there is not enough memory, the memory of these objects is reclaimed. As long as the garbage collector does not collect it, * the object can be used by the program. * * / public class SoftReference1 { public static void main(String[] args) { SoftReference<byte[]> m = new SoftReference<>(new byte[1024*1024*10]); System.out.println(m.get()); System.gc(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(m.get()); // Re-allocate an array, the heap will not fit, the JVM will recycle once, if not, the reference will be drained byte[] b = new byte[1024*1024*12]; System.out.println(m.get()); }}Copy the code
Note that when testing, you need to set parameters, the size of the JVM.
-
Click Run for IDEA, then click Run, select Edit Configurations, and enter the following parameters in VM Options
-Xms20M -XMx20m Indicates that the maximum and minimum heap memory is 20M
When out of memory, the JVM first sets the object reference in the soft reference to NULL and then tells the garbage collector to collect:
if(JVM out of memory) {// Set object references in soft references to NULL str = null; // Notify the garbage collector to collect System.gc(); } Copy the code
Application Scenarios:
The browser’s back button. When you press Back, is the content of the page displayed on the back page rerequested or retrieved from the cache? It depends on the implementation strategy.
- If a web page is recycled at the end of browsing, it needs to be rebuilt when you click back to view previously viewed pages.
- If the browsed web pages are stored in memory, it will cause a large amount of memory waste, and even cause memory overflow.
-
3. The weak:
-
Caches, which need to be cleared when there is no container reference to point to
-
ThreadLocal, WeakHasMap
-
The difference between weak and soft references is that objects with only weak references have a shorter lifetime. When the garbage collector thread scans the memory area under its control, once it finds an object with only weak references, it reclaims its memory regardless of whether the current memory space is sufficient. However, because the garbage collector is a low-priority thread, objects that have only weak references are not necessarily found quickly.
package com.anzhi.Reference; import java.lang.ref.WeakReference; /* * When the garbage collector thread scans the memory area under its control and finds an object with only weak references, * reclaims its memory regardless of whether the current memory space is sufficient or not. However, because the garbage collector is a low-priority thread, objects that have only weak references are not necessarily found quickly. * * / public class WeakReference1 { public static void main(String[] args) { WeakReference<M> m = new WeakReference<>(new M("zhangsan")); System.out.println(m.get()); System.gc(); System.out.println(m.get()); ThreadLocal<WeakReference1> t = new ThreadLocal<>(); t.set(newWeakReference1()); t.remove(); }}Copy the code
-
Application Scenarios:
-
Commonly used in containers
-
The classic is the ThreadLocal application
As described earlier, each ThreadLocal is a collection of maps maintained by ThreadLocalMap, and each node corresponds to a Thread. The type of key is a weak reference
/** * The entries in this hash map extend WeakReference, using * its main ref field as the key (which is always a * ThreadLocal object). Note that null keys (i.e. entry.get() * == null) mean that the key is no longer referenced, so the * entry can be expunged from table. Such entries are referred to * as "stale entries" in the code that follows. * / 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
Why do Entries use weak references?
If the type of k is a strong reference, even if t=null; However, the reference to the key still refers to the T object and is not collected by the GC, causing a memory leak. Weak references do not. However, there is another problem: when T is collected by GC, the key points to NULL, and the value of value cannot be accessed any more, and there is still a memory leak, so you need to remove it manually.
Key =null does not mean that the value Object is not referenced. ThreadLocalMap is still in place. It contains a collection of entries whose Object value refers to the value Object, so it will not be collected by GC
-
4. :
-
Manage off-heap memory
- As the name implies, a virtual reference is a virtual reference. Unlike the other references, virtual references do not determine the lifetime of the object. If an object holds only virtual references, it can be collected by the garbage collector at any time, just as if there were no references at all.
- 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. If the program finds that a virtual reference has been added to the reference queue, it can take the necessary action before the memory of the referenced object is reclaimed.
package com.anzhi.Reference; import java.lang.ref.PhantomReference; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.util.LinkedList; import java.util.List; /** ** * The existence of a virtual reference does not affect the lifetime of an object, and it is impossible to obtain an instance of an object through a virtual reference. * The sole purpose of setting a virtual reference association for an object is to receive a system notification when the object is reclaimed by the collector. * Neither virtual references nor weak references have an effect on the collection of the associated object. If only the virtual references or weak references are associated with the object, the object will be recycled. The difference is that the get method for weak references, the get method for virtual references always returns NULL, * Weak references can be used with ReferenceQueue, and virtual references must be used with ReferenceQueue. Addressing Unsafe issues, the JDK also uses virtual references to allocate and reclaim direct memory. The JVM's automatic memory management is in the heap, and its immediate memory is not in the heap. After Java claims a chunk of direct memory, * allocates an object in the heap to hold a reference to the out-of-heap memory. * This object is managed by the garbage collector, and once the object is reclaimed, * the corresponding user thread is notified to clean up the direct memory. In fact, one of the most important uses of virtual references is to free out-of-heap memory. DirectByteBuffer uses virtual references to free out-of-heap memory. * * / public class PhantomReference1 { 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 object reclaimed by JVM ----" + poll); } } }).start(); try { Thread.sleep(500); } catch(InterruptedException e) { e.printStackTrace(); }}}Copy the code
Generally not used, for the use of development JVM.