Lock与Condition接口
前面两篇文章回顾了传统的synchronized
关键字、JMM内存模型、volitile
关键字,这篇文章开始我们正式介绍juc
包。
在jdk5之后,juc提供了Lock
,与synchronized
相似,都可以实现锁功能,但是需要手动获取锁和释放锁。不过它与synchronized
又不太一样,synchronized
关键字相当于是使用的其它类的monitor关联,在mark word
中记录锁的信息。而Lock
则可以认为是一个锁对象。
看看Lock
源码的方法。
public interface Lock { | |
//获取锁 | |
void lock(); | |
// 获取锁,等待过程中响应中断 | |
void lockInterruptibly() throws InterruptedException; | |
// 尝试获取锁,不会阻塞,成功则返回true,否则返回false | |
boolean tryLock(); | |
// 尝试获取锁,如果获取不到则等待限定时间,超时未获取锁则返回false,可以响应中断 | |
boolean tryLock(long time, TimeUnit unit) throws InterruptedException; | |
//释放锁 | |
void unlock(); | |
// 可以理解为wait、notify的替代方案 | |
Condition newCondition(); | |
} |
简单应用下。
public class Demo8 { | |
private static int i = 0; | |
public static void main(String[] args) throws InterruptedException { | |
Lock lock = new ReentrantLock(); | |
Runnable action = () -> { | |
for (int j = 0; j < 100000; j++) { | |
lock.lock(); | |
i ++; | |
lock.unlock(); | |
} | |
}; | |
new Thread(action).start(); | |
new Thread(action).start(); | |
Thread.sleep(1000); | |
System.out.println(i); | |
} | |
} |
可以看到,使用Lock
,是真正的在操作一个锁对象。
使用synchronized
可以进行wait
和notify
。
synchronized (Demo8.class) { | |
Demo8.class.wait(); | |
} |
使用Lock
配合condition
接口可以实现类似功能。而且,使用synchronized
关键字只能使用其加锁对象的wait
和notify
方法,只能有一个等待队列,就是加锁对象(如Demo8.class)的等待队列。而使用Lock
和Condition
则可以有多个等待队列。
来一起阅读下Condition
类的源码。
public interface Condition { | |
// 对应wait()方法,需要signal()或者signalAll()唤醒,可以响应中断 | |
void await() throws InterruptedException; | |
// 等待,不响应中断 | |
void awaitUninterruptibly(); | |
// 等待指定时间(纳秒),如果未超时被唤醒则返回剩余时间,超时返回false,可以响应中断 | |
long awaitNanos(long nanosTimeout) throws InterruptedException; | |
// 等待指定时间,如果未超时被唤醒则返回true,超时返回0或者负数,可以响应中断 | |
boolean await(long time, TimeUnit unit) throws InterruptedException; | |
// 指定明确的时间点,在该时间点前被唤醒则返回true,否则false,可以响应中断 | |
boolean awaitUntil(Date deadline) throws InterruptedException; | |
// 唤醒任一线程,该线程进入就绪状态 | |
void signal(); | |
// 唤醒所有线程 | |
void signalAll(); | |
} |
下面实战使用下。
public class Demo9 { | |
public static void main(String[] args) throws InterruptedException { | |
Lock lock = new ReentrantLock(); | |
Condition condition = lock.newCondition(); | |
new Thread(() -> { | |
lock.lock(); | |
System.out.println("await...."); | |
try { | |
condition.await(); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
System.out.println("await finished"); | |
lock.unlock(); | |
}).start(); | |
Thread.sleep(100); | |
new Thread(() -> { | |
lock.lock(); | |
System.out.println("signal..."); | |
condition.signal(); | |
System.out.println("thread 2 finished"); | |
lock.unlock(); | |
}).start(); | |
} | |
} |
输出的结果如下。
await.... | |
signal... | |
thread 2 finished | |
await finished |
值的关注的一点是,不管使用await
还是signal
都要在获取锁的前提下。这与wait
与notify
实际上是一致的。不过,在使用了await
以后,锁就被释放了,否则主线程也不可能继续执行。
和sychronized
关键字不同的是,同一把锁可以创建多个Condition
,每个Condition
对象都拥有独立的等待队列。看如下代码。
public class Demo9 { | |
public static void main(String[] args) throws InterruptedException { | |
Lock lock = new ReentrantLock(); | |
Condition condition = lock.newCondition(); | |
Condition condition1 = lock.newCondition(); | |
new Thread(() -> { | |
lock.lock(); | |
System.out.println("await...."); | |
try { | |
condition.await(); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
System.out.println("await finished"); | |
lock.unlock(); | |
}).start(); | |
Thread.sleep(100); | |
new Thread(() -> { | |
lock.lock(); | |
System.out.println("signal..."); | |
condition1.signal(); | |
System.out.println("thread 2 finished"); | |
lock.unlock(); | |
}).start(); | |
} | |
} |
其输出结果如下。
await.... | |
signal... | |
thread 2 finished |
显然,condition1
的signal
没能唤醒condition
的await
的线程。
当然,也并不是用了await
就需要signal
,因为可以限定时长。
public class Demo10 { | |
public static void main(String[] args) throws InterruptedException { | |
Lock lock = new ReentrantLock(); | |
Condition condition = lock.newCondition(); | |
lock.lock(); | |
try { | |
System.out.println(condition.await(3, TimeUnit.SECONDS)); | |
} finally { | |
lock.unlock(); | |
} | |
} | |
} |
打印结果为false,因为超过3s也没有被唤醒。