Master high concurrency, high availability architecture
Lesson 2 Concurrent Programming
Learn concurrent programming from this lesson. This paper mainly introduces the basic knowledge of concurrent programming, lock, memory model, thread pool and the use of various concurrent containers.
Section 4 Thread Communication
Concurrent Programming Thread Communication AQS Condition Lock
This section learns about communication between threads and handwritten cache queues.
Implementation of Thread Communication
There are two kinds:
- Keywords synchronized with wait(), notify(), notify all () to achieve
- Using Lock and Condition s
This section focuses on Condition.
Condition
It's an interface. The implementation class is ConditionObject, an internal class of AQS
public interface Condition { void await() throws InterruptedException; void awaitUnInterruptibly(); long awaitNanos(long nanosTimeout) throws InterruptedException; boolean await(long time, TimeUnit unit) throws InterruptedException; boolean awaitUntil(Date deadline) throws InterruptedException; void signal(); void signalAll(); }
- await() causes the current thread to wait and release the lock; when other threads execute signal() or signalAll(), the thread retrieves the lock and continues to execute; or when the thread is interrupted, it causes the thread to jump out of the wait. This method is similar to Object.wait().
- awaitUnInterruptibly(), similar to await, does not respond to interruptions, even in a waiting state
- signal(), used to wake up a waiting thread. The relative signalAll() method wakes up all waiting threads. Similar to Object.notify()
condition.await() must be used between lock and unlock
Use lock. new Condition () to get the Condition
False Waiting and False Awakening
When await() or signal() is executed, the thread does not necessarily respond immediately, and false waiting and false wake-up occur. This is a concession to the semantics of the underlying platform. If you use "if (! Condition)" to make judgments, there will be problems, so generally use "while(! Condition)" to prevent this situation.
No IF, WHILE
if (!condition) { condition.await(); }
while (!condition) { condition.await(); }
Implementation of Buffer Queue
Upper Code (Producer-Consumer Model)
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Description: Buffer queue * @Author: lsw * @Version: 1.0 */ public class BoundedBuffer { final Lock lock = new ReentrantLock(); // Lock object final Condition notFull = lock.newCondition(); // Writing Conditions final Condition notEmpty = lock.newCondition(); // Reading Conditions final Object[] items = new Object[100]; // container int putIdx, // Write an index takeIdx, // Reading Index count; // Current Quantity public void put(Object it) throws InterruptedException { lock.lock(); try { while (count == items.length) { notFull.await(); // When the container is full, make the write thread wait } // Normal Conditions items[putIdx] = it; putIdx++; // Save it to the end and start again. if (putIdx == items.length) { putIdx = 0; } count++; // Save in the object and read on the notification reader thread notEmpty.signal(); } finally { lock.unlock(); } } public Object take() throws InterruptedException { lock.lock(); try { while (count == 0) { notEmpty.await(); // When the container is empty, the reader thread waits } // Normal Conditions Object it = items[takeIdx]; takeIdx++; // If you read to the end, start from scratch if (takeIdx == items.length) { takeIdx = 0; } count--; // Wake-up Write Thread notFull.signal(); return it; } finally { lock.unlock(); } } }
By creating multiple conditions for the same Lock, you can very flexibly control the execution or waiting of each thread. That's the strength of Condition.
LockSupport Tool Class
LockSupport.part() or LockSupport.unpark() will be used at the bottom when Lock is used to implement lock and unlock and Condition s are used to perform state operations on threads. Now let's look at this tool class.
public class LockSupport { static void park() {} static void park(Object blocker) {} static void parkNanos(long nanos) {} static void parkNanos(Object blocker, long nanos) {} static void parkUntil(long deadline) {} static void park(Object blocker, long deadline) {} static void unpark(Thread t) {} }
The function of the park() method is to cause the current thread to enter a waiting WAITING queue until unpark() is called or the response interrupts.
The parkNanos() method is to cause the current thread to enter the waiting queue, and the waiting time should not exceed the specified time.
The parkUntil() method is to cause the current thread to enter a waiting queue until it exits at a deadline.
The parameter blocker is an object that can be used to record the waiting of threads to facilitate problem checking.
unpark() is used to wake up a specified thread
Underneath these functions are UNSAFE.park() and UNSAFE.unpark() of the invoked Unsafe local class library.