[multithreading and high concurrency] 4-AQS & strong weak virtual

Posted by PaulRyan on Wed, 29 Dec 2021 05:21:26 +0100

AQS(CLH)

Bottom layer: CAS+volatile

graphic

The core of aqs is a state (volatile) and a two-way linked list that monitors the state. Each linked list has a node and each node is loaded with threads. If each thread wants to obtain a lock and wait, it must enter the waiting queue.
(when adding the tail of the queue, we should pay attention to the front node, perform CAS to prevent thread interruption, and add spin waiting to the tail instead of sync for chain table, which is the core of high efficiency)

  • ReentrantLock: state records how many times the thread re enters. When it becomes 0, it is released.
  • Join the waiting queue: jdk1.0 is used in the addWaiter method 9. Varhandle type (reference to variable), which can perform atomic operations (operation of common attributes), is similar to reflection, but is efficient.
    varHandle:
    1. General attribute atomic operation
    2. Faster than reflection, direct operation of binary code
int x = 8;
private static VarHandle handle;
static {
    try {
        handle = MethodHandles.lookup().findVarHandle(T01_HelloVarHandle.class, "x", int.class);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) {
    T01_HelloVarHandle t = new T01_HelloVarHandle();
    //plain read / write
    System.out.println((int)handle.get(t));
    handle.set(t,9);
    System.out.println(t.x);
    handle.compareAndSet(t, 9, 10);
    System.out.println(t.x);
    handle.getAndAdd(t, 10);
    System.out.println(t.x);
}

ThreadLocal

Concurrency is easy to occur when multiple threads access the same shared variable, especially when multiple threads write to a variable. In order to ensure thread safety, general users need to take additional synchronization measures when accessing shared variables to ensure thread safety.
ThreadLocal is a guarantee other than locking. It is a method to avoid thread insecurity in multi-threaded access. After creating a variable, if each thread accesses its own variables, there will be no thread insecurity.

Source code

  • set
    Thread.currentThread.map(ThreadLocal,person)
    Set to the map of the current thread.
  • purpose
    Declarative transaction to ensure the same Connection
public class ThreadLocal2 {
	//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";
	}
}

Weak and weak

  • Strong reference
    Strong references are the most commonly used references. If an object has a strong reference, the garbage collector will never recycle it. As follows:
    Object strongReference = new Object();
    When the memory space is insufficient, the Java virtual machine would rather throw OutOfMemoryError error to make the program terminate abnormally, rather than solve the problem of insufficient memory by arbitrarily recycling objects with strong references.

  • Soft reference: Reclaim when memory is insufficient, mostly for caching
    Soft references are used to describe some useful but not necessary objects.
    For objects associated with soft references, these objects will be listed in the recycling range for the second recycling before the memory overflow exception will occur in the system. If there is not enough memory for this recycle, a memory overflow exception will be thrown- Xmx20M

  • Weak reference
    As long as GC is encountered, it is directly recycled, which is generally used for containers

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(); //To clear
}

Why should entries use weak references?
If it is a strong reference, even if tl=null, the reference of the key still points to the ThreadLocal object, so there will be a memory leak, but using a weak reference will not.
However, there will still be a memory leak. ThreadLocal is recycled and the value of key becomes null, resulting in the whole value can no longer be accessed. Therefore, there is still a memory leak.
So you must remove in the end

  • Virtual reference - off heap memory (for the person who writes the jvm)

Whether an object has a virtual reference will not affect its lifetime, nor can it be used to obtain an object instance through virtual reference.
The only purpose of setting a virtual reference Association for an object is to receive a system notification when the object is recycled by the collector.
Virtual reference and weak reference will not affect the recycling of associated objects. If only virtual reference is alive and weak reference is associated with the object, the object will be recycled. Their difference lies in the get method of weak reference. The get method of virtual reference always returns null. Weak reference can use ReferenceQueue, and virtual reference must be used with ReferenceQueue.
Virtual references are used for direct memory recovery in jdk, because the scope of jvm automatic memory management is heap memory, Direct memory is outside heap memory (in fact, it is a memory mapping file), so the direct memory allocation and recycling are operated by the Unsafe class. After java applies for a piece of direct memory, it will allocate an object in the heap memory to save the reference of the off heap memory. The object is managed by the garbage collector. Once the object is recycled, the corresponding user thread will receive a notification and clean up the direct memory Work. In fact, a very important use of virtual reference is to release the off heap memory. DirectByteBuffer is used to release the off heap memory through virtual reference.

Topics: Multithreading Concurrent Programming