Lock与Synchronized相比的优势:
- 相比于Synchronized, Lock更加灵活,可以关联不同的Condition;
- Lock中的RenentrantLock是可重入锁;
- 可以定义优先级或者公平锁;
lock.lock()一定要配对 lock.unlock(),并且 lock.unlock()放在finally块中,使得任何情况下都会解锁;
await() 源码详解
- 与当前Condition对象相关联的锁被当前线程释放,处于休眠状态,直到
- 另一个线程 signal 或者 signalAll 唤醒了当前线程;
- 另一个线程中断了当前线程;
- 虚假唤醒。
/**
* Causes the current thread to wait until it is signalled or
* {@linkplain Thread#interrupt interrupted}.
*
* <p>The lock associated with this {@code Condition} is atomically
* released and the current thread becomes disabled for thread scheduling
* purposes and lies dormant until <em>one</em> of four things happens:
* <ul>
* <li>Some other thread invokes the {@link #signal} method for this
* {@code Condition} and the current thread happens to be chosen as the
* thread to be awakened; or
* <li>Some other thread invokes the {@link #signalAll} method for this
* {@code Condition}; or
* <li>Some other thread {@linkplain Thread#interrupt interrupts} the
* current thread, and interruption of thread suspension is supported; or
* <li>A "<em>spurious wakeup</em>" occurs.
* </ul>
*
* <p>In all cases, before this method can return the current thread must
* re-acquire the lock associated with this condition. When the
* thread returns it is <em>guaranteed</em> to hold this lock.
*
* <p>If the current thread:
* <ul>
* <li>has its interrupted status set on entry to this method; or
* <li>is {@linkplain Thread#interrupt interrupted} while waiting
* and interruption of thread suspension is supported,
* </ul>
* then {@link InterruptedException} is thrown and the current thread's
* interrupted status is cleared. It is not specified, in the first
* case, whether or not the test for interruption occurs before the lock
* is released.
*
* <p><b>Implementation Considerations</b>
*
* <p>The current thread is assumed to hold the lock associated with this
* {@code Condition} when this method is called.
* It is up to the implementation to determine if this is
* the case and if not, how to respond. Typically, an exception will be
* thrown (such as {@link IllegalMonitorStateException}) and the
* implementation must document that fact.
*
* <p>An implementation can favor responding to an interrupt over normal
* method return in response to a signal. In that case the implementation
* must ensure that the signal is redirected to another waiting thread, if
* there is one.
*
* @throws InterruptedException if the current thread is interrupted
* (and interruption of thread suspension is supported)
*/
signal() 源码详解
- 唤醒一个等待在这个Condition对象上的线程;
- 当前线程必须持有与Condition对象相关的lock,否则抛出IllegalMonitorStateException异常。
/**
* Wakes up one waiting thread.
*
* <p>If any threads are waiting on this condition then one
* is selected for waking up. That thread must then re-acquire the
* lock before returning from {@code await}.
*
* <p><b>Implementation Considerations</b>
*
* <p>An implementation may (and typically does) require that the
* current thread hold the lock associated with this {@code
* Condition} when this method is called. Implementations must
* document this precondition and any actions taken if the lock is
* not held. Typically, an exception such as {@link
* IllegalMonitorStateException} will be thrown.
*/
package thread;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//用lock,condition实现生产者消费者模式
public class ProducerConsumer2 {
static Lock lock = new ReentrantLock();
static Condition queueEmpty = lock.newCondition();
static Condition queueFull = lock.newCondition();
public static void main(String[] args) throws InterruptedException {
Queue<Integer> queue = new LinkedList<>();
Producer p1 = new Producer(queue);
Consumer c1 = new Consumer(queue);
p1.start();
c1.start();
p1.join();
c1.join();
}
static class Producer extends Thread {
Queue<Integer> queue;
public Producer(Queue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
lock.lock();
try {
while (!queue.isEmpty()) {
queueEmpty.await();
}
int tmp = new Random().nextInt();
queue.offer(tmp);
queueFull.signalAll();
System.out.println("Producing " + tmp);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
static class Consumer extends Thread {
Queue<Integer> queue;
public Consumer(Queue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
lock.lock();
try {
while (queue.isEmpty()) {
queueFull.await();
}
int tmp = queue.poll();
queueEmpty.signalAll();
System.out.println("Consuming " + tmp);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}