LockSupport
Locksupport.park (), locksupport.unpark (Thread) can block or release a Thread. It is relatively flexible, and. Unpark (Thread) can be executed ahead of time without blocking when park() is executed
The interview questions
Interview question: Write a fixed-capacity synchronous container with put and GET methods and getCount methods,
It can support blocking calls from 2 producer threads and 10 consumer threadsCopy the code
public class syncContainer { private final LinkedList<T> lists = new LinkedList(); private final int MAX=10; private int count =0; public synchronized void put(T t){ while (lists.size()== MAX){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } count++; lists.add(t); this.notifyAll(); } } public synchronized T get(){ while (lists.size()==0){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } T t = lists.removeFirst(); count--; this.notifyAll(); return t; }}Copy the code
In-depth interpretation of AQS source code
Honestly see source is best able to run the source code, fire watch is easy to go to the dead end, the best is to put the code to run, we are chasing the code, it can better know his story, and then according to their own memory draw his class dependencies, and the call to each class of method to deepen our memory.
ReentrantLock Unlocking flowchart
Dig into how each detail was handled
static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; /** * Performs lock. Try immediate barge, Backing up to normal * acquire on failure. */ final void lock() {if (compareAndSetState(0, SetExclusiveOwnerThread (thread.currentThread ()); else acquire(1); }}Copy the code
public final void acquire(int arg) { // if (! tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } protected final Boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires); } final Boolean nonfairTryAcquire(int acquires) {final Thread current = thread.currentThread (); Int c = getState(); If (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current); setExclusiveOwnerThread(current); return true; Else if (current == getExclusiveOwnerThread()) {int nexTC = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); // Update state setState(nexTC); return true; } // Return false if no lock is obtained; } private NODE addWaiter(NODE mode) {NODE NODE = new NODE (thread.currentThread (), mode); // Try the fast path of enq; // set pred to last node. Node pred = tail; // If pred is not null if (pred! = null) { node.prev = pred; If (compareAndSetTail(pred, node)) {pred. Next = node; return node; }} // if tail is null enq(node); return node; } private Node enq(final Node node) { for (;;) { Node t = tail; If (t == null) {Must initialize if (compareAndSetHead(new node ())) tail = head; } else { node.prev = t; If (compareAndSetTail(t, node)) {t.ext = node; // If tail is not null append a node to it. return t; } } } } final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) Final node p = node.predecessor(); If (p == head && tryAcquire(arg)) {// If (p == head && tryAcquire(arg)) {// If (p == head && tryAcquire(arg)) { p.next = null; // help GC failed = false; return interrupted; } // Attempted to acquire the lock, but failed (possibly because of p! = head) if (shouldParkAfterFailedAcquire (p, node) && parkAndCheckInterrupt ()) interrupted = true; } } finally { if (failed) cancelAcquire(node); }} // Attempted to acquire the lock, but failed (possibly because of p! = head) private static Boolean shouldParkAfterFailedAcquire (Node Mr Pred, Node Node) {int ws = Mr Pred. WaitStatus; If (ws == node. SIGNAL) /* * The precursor Node has set SIGNAL, the alarm has been set, and now I can sleep peacefully (blocked). * If the head is head and the head delegate thread exclusiveOwnerThread releases the lock, */ * This node has already set status asking a release * to SIGNAL it, so it can safely park. */ return true; CANCELLED if (ws > 0) {* * The state of the incoming precursor is found to be greater than 0. The precursor node has cancelled itself because it timed out or responded to an interrupt, *. So you need to jump over these CANCELLED nodes, Until a <=0 node is found */ /* * Predecessor was cancelled. Skip over boomtime and * indicate retry. */ do {node.prev = pred = pred.prev; } while (pred.waitStatus > 0); pred.next = node; } else {* * Into this branch, ws can only be 0 or PROPAGATE. Indicate that we * need a SIGNAL, but don't park yet. Caller will need to * retry to make sure it cannot acquire before parking. */ compareAndSetWaitStatus(pred, ws, Node.SIGNAL); } return false; }Copy the code
Analyze the unlocking code by yourself. One important thing is that multiple locks may be added, so we need to unlock them one by one.
VarHandler
VarHandler (); VarHandler (); VarHandler ();
reference
- Strong references: As long as an object is associated with a strong reference, the JVM would rather throw an outOfMemoryError than reclaim such an object if it is out of memory.
- Soft References: SoftRefence is used in Java to represent soft references, and if an object is associated with a soft reference, the JVM will only reclaim that object if it is out of memory. With this feature, soft references can be used for caching.
- Weak References: Weak references are used in Java to represent weak references. If an object is associated with a weak reference, then when the JVM does garbage collection, it will reclaim that object regardless of whether there is sufficient memory.
- Virtual References: Java uses PhantomReference to represent virtual references. Virtual references, virtual references, references are just like nothing, just like an object that has no reference associated with it. If an object is associated with a virtual reference, it can be reclaimed by the JVM at any time. Virtual references cannot be used alone and must be used in conjunction with reference queues.