Ref:
- https://stackoverflow.com/a/56659651/8945448
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/LockSupport.html
Synchronized 实现阻塞等待
@Test
public void test_objWaitNotify() throws InterruptedException {
Object lock = new Object();
Runnable task1 = () -> {
synchronized (lock) {
System.out.printf("%s get lock. %n", Thread.currentThread().getName());
try {
// release lock
lock.wait();
System.out.printf("%s get resumed. %n", Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread thread1 = new Thread(task1);
thread1.setName("Thread1");
thread1.start();
Runnable task2 = () -> {
synchronized (lock) {
System.out.printf("%s get lock. %n", Thread.currentThread().getName());
lock.notify();
try {
System.out.printf("%s notify other threads. %n", Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("%s synchronized() done and release lock. %n", Thread.currentThread().getName());
}
};
Thread thread2 = new Thread(task2);
thread2.setName("Thread2");
thread2.start();
// block main thread waiting for sub-threads
TimeUnit.SECONDS.sleep(1);
}
LockSupport.park()
park() method:
Disables the current thread for thread scheduling purposes unless the permit is available./**
* Disables the current thread for thread scheduling purposes unless the
* permit is available.
*
* <p>If the permit is available then it is consumed and the call returns
* immediately; otherwise
* the current thread becomes disabled for thread scheduling
* purposes and lies dormant until one of three things happens:
*
* <ul>
* <li>Some other thread invokes {@link #unpark unpark} with the
* current thread as the target; or
*
* <li>Some other thread {@linkplain Thread#interrupt interrupts}
* the current thread; or
*
* <li>The call spuriously (that is, for no reason) returns.
* </ul>
*
* <p>This method does <em>not</em> report which of these caused the
* method to return. Callers should re-check the conditions which caused
* the thread to park in the first place. Callers may also determine,
* for example, the interrupt status of the thread upon return.
*
* @param blocker the synchronization object responsible for this
* thread parking
* @since 1.6
*/
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
setBlocker(t, null);
}
自定义队列锁:
class FIFOMutex {
private final AtomicBoolean locked = new AtomicBoolean(false);
private final Queue<Thread> waiters
= new ConcurrentLinkedQueue<Thread>();
public void lock() {
boolean wasInterrupted = false;
Thread current = Thread.currentThread();
waiters.add(current);
// Block while not first in queue or cannot acquire lock
while (waiters.peek() != current ||
!locked.compareAndSet(false, true)) {
LockSupport.park(this);
if (Thread.interrupted()) // ignore interrupts while waiting
wasInterrupted = true;
}
waiters.remove();
if (wasInterrupted) // reassert interrupt status on exit
current.interrupt();
}
public void unlock() {
locked.set(false);
LockSupport.unpark(waiters.peek());
}
}