接口Lock
首先我们回顾下同步代码块,例如:
Object obj =
new Object();
void show(){
synchronized(obj){
code...
}
}
同步代码块对锁的操作是隐式的,执行完同步代码块中的内容,自动释放锁。而Lock将锁封装成为了对象,即把对锁操作的隐式操作换成了显示操作。可以将如上代码改写:
Lock lock = new ReentrantLock();
void
show(){
lock.lock();//获取锁
code...
lock.unlock();//释放锁
}
jdk1.5之后将同步和锁封装成了对象,并将操作锁的隐式方式定义到了该对象中,将隐式动作变成了显示动作。 上述代码中存在隐患,例如code部门产生异常throw Exception的话,会导致后面代码无法执行,即没有释放锁,因此需要将释放锁的操作放在finally块中。
Lock
lock =
new ReentrantLock();
void show(){
lock.
lock();
try{
code...
}
finally{
lock.unlock();
}
}
Condition newCondition():返回绑定到此Lock实例的新Condition实例
接口Condition
public interface Condition ,Condition将Object监视器方法(wait,notify和notifyAll)分解成截然不同的对象,以便通过将这些对象与任意Lock实现组合使用,为每个对象提供多个等待set(wait-set)。其中,Lock替代了synchronized方法和语句的使用,Condition替代了Object监视器方法的使用。
条件(也称为条件队列或条件变量)为线程提供一个含义,以便在某个状态条件现在可能为true的另一个线程通知它之前,一直挂起该线程(即让其“等待”)。因为访问此共享状态信息发生在不同的线程中,所以它必须受保护,因此要将某种形式的锁与该条件相关联。等待提供一个条件的主要属性是:以原子方式释放相关的锁,并挂起当前线程,就像Object.wait做的那样。
Condition实例实质上被绑定到一个锁上。要为特定Lock实例获得Condition实例,请使用其newCondition()方法。
具体是什么意思呢,个人用自己的理解白话解释下:
正常的传统synchronized块方式,每个锁对象obj对应有一套*wait,notify,notifyAll方法(因为不同锁对象的wait和notify是不起作用的),而Condition对wait,notify,notifyAll方法进行了封装,多个Condition对象可以同时所属于同一个Lock锁对象*
常用方法:
await():造成当前线程在接收到信号或被中断之前一直处于等待状态await(long time,TimeUnit unit):造成当前线程在接收到信号、被中断或者到达指定等待时间之前一直处于等待状态signal():唤醒一个等待线程signalAll():唤醒所有等待线程
传统锁与Condition使用简单对比
传统方式:
class Object{
wait();
notify();
notifyAll();
}
class Demo extends Object{
}
Demo d =
new Demo();
synchronized(d){
d.wait;
}
Condition方式:
interface Condition{
await();
signal();
signalAll();
}
Lock
lock =
new ReentrantLock();
Condition c1 =
lock.newCondition();
Condition c2 =
lock.newCondition();
由上可以发现Lock的目的是为了替代同步,Condition的目的是为了替代Object中的方法
Lock方式实现学习笔记(五)中的需求
class ResourceDemo{
private String name;
private int count;
private boolean flag =
false;
Lock lock =
new ReentrantLock();
Condition con = lock.newCondition();
public void set(String name){
lock.lock();
try{
while (flag){
try{
con.await();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name +
count;
count++;
System.out.println(Thread.currentThread().getName()+
"...生产者..."+
this.name);
flag =
true;
con.signalAll();
}
finally {
lock.unlock();
}
}
public void out(){
lock.lock();
try{
while (!flag){
try{
con.await();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+
"......消费者......"+
this.name);
flag =
false;
con.signalAll();
}
finally {
lock.unlock();
}
}
}
class Producer implements Runnable{
private ResourceDemo r;
Producer(ResourceDemo r){
this.r = r;
}
public void run(){
while (
true){
r.set(
"烤鸭");
}
}
}
class Consumer implements Runnable{
private ResourceDemo r;
Consumer(ResourceDemo r){
this.r = r;
}
public void run(){
while (
true){
r.out();
}
}
}
public class ProducerConsumerDemo {
public static void main(String[] args){
ResourceDemo r =
new ResourceDemo();
Producer pro =
new Producer(r);
Consumer con =
new Consumer(r);
Thread t0 =
new Thread(pro);
Thread t1 =
new Thread(pro);
Thread t2 =
new Thread(con);
Thread t3 =
new Thread(con);
t0.start();
t1.start();
t2.start();
t3.start();
}
}
注意点:
使用while而不是if使用signalAll()而不是signal()
具体原因解释可以参见之前博客:http://blog.csdn.net/megustas_jjc/article/details/71107387
Lock优势
使用两个监视器,一组监视生产者,一组监视消费者,而之前的传统方法要想实现,需要两个锁,因为传统方式一把锁上只有一组监视器,而Lock的方式,一把锁上可以绑定多组监视器。因此可以实现“唤醒对方线程”,解决了之前传统方法notifyAll方式的效率低的问题。
最终Lock方式的实现代码
class ResourceDemo{
private String name;
private int count;
private boolean flag =
false;
Lock
lock =
new ReentrantLock();
Condition producer_con =
lock.newCondition();
Condition consumer_con =
lock.newCondition();
public void set(String name){
lock.
lock();
try{
while (flag){
try{
producer_con.
await();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name + count;
count++;
System.
out.println(Thread.currentThread().getName()+
"...生产者..."+
this.name);
flag =
true;
consumer_con.signalAll();
}
finally {
lock.unlock();
}
}
public void out(){
lock.
lock();
try{
while (!flag){
try{
consumer_con.
await();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
System.
out.println(Thread.currentThread().getName()+
"......消费者......"+
this.name);
flag =
false;
producer_con.signalAll();
}
finally {
lock.unlock();
}
}
}
class Producer implements Runnable{
private ResourceDemo r;
Producer(ResourceDemo r){
this.r = r;
}
public void run(){
while (
true){
r.
set(
"烤鸭");
}
}
}
class Consumer implements Runnable{
private ResourceDemo r;
Consumer(ResourceDemo r){
this.r = r;
}
public void run(){
while (
true){
r.
out();
}
}
}
public class ProducerConsumerDemo {
public static void main(String[] args){
ResourceDemo r =
new ResourceDemo();
Producer pro =
new Producer(r);
Consumer con =
new Consumer(r);
Thread t0 =
new Thread(pro);
Thread t1 =
new Thread(pro);
Thread t2 =
new Thread(con);
Thread t3 =
new Thread(con);
t0.start();
t1.start();
t2.start();
t3.start();
}
}