黑马程序员——Lock锁与Condition

------- android培训java培训、期待与您交流! ----------

1.publicinterface Lock

.Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。

.锁定是控制多个线程对共享资源进行访问的工具。通常,锁定提供了对共享资源的独占访问。一次只能有一个线程获得锁定,对共享资源的所有访问都需要首先获得锁定。不过,某些锁定可能允许对共享资源并发访问,如 RedWriteLock的读取锁定。

.synchronized 方法或语句的使用提供了对与每个对象相关的隐式监视器锁定的访问,但却强制所有锁定获取和释放均要出现在一个块结构中:当获取了多个锁定时,它们必须以相反的顺序释放,且必须在与所有锁定被获取时相同的词法范围内释放所有锁定。

虽然 synchronized 方法和语句的范围机制使得使用监视器锁定编程方便了很多,而且还帮助避免了很多涉及到锁定的常见编程错误,但有时也需要以更为灵活的方式使用锁定。例如,某些遍历并发访问的数据结果的算法要求使用"hand-over-hand" "chain locking":获取节点 A的锁定,然后再获取节点 B的锁定,然后释放 A并获取 C,然后释放 B并获取 D,依此类推。Lock 接口的实现允许锁定在不同的作用范围内获取和释放,并允许以任何顺序获取和释放多个锁定,从而支持使用这种技术。

.随着灵活性的增加,也带来了更多的责任。不使用块结构锁定就失去了使用 synchronized 方法和语句时会出现的锁定自动释放功能。在大多数情况下,应该使用以下语句:

     Lock l = ...;

     l.lock();

     try {

              } finally {

         l.unlock();

     }

 

.锁定和取消锁定出现在不同作用范围中时,必须谨慎地确保保持锁定时所执行的所有代码用 try-finally try-catch加以保护,以确保在必要时释放锁定。

.Lock 实现提供了使用 synchronized 方法和语句所没有的其他功能,包括提供了一个非块结构的获取锁定尝试 (tryLock())、一个获取可中断锁定的尝试 (lockInterruptibly())和一个获取超时失效锁定的尝试 (tryLock())

p.Lock 类还可以提供与隐式监视器锁定完全不同的行为和语义,如保证排序、非重入用法或死锁检测。如果某个实现提供了这样特殊的语义,则该实现必须对这些语义加以记录。

q.注意,Lock 实例只是普通的对象,其本身可以在 synchronized 语句中作为目标使用。获取 Lock 实例的监视器锁定与调用该实例的任何lock()方法没有特别的关系。为了避免混淆,建议除了在其自身的实现中之外,决不要以这种方式使用 Lock 实例。

除非另有说明,否则为任何参数传递 null 值都将导致抛出 NullPoiterException

2.内存同步

所有 Lock 实现都必须 实施与内置监视器锁定提供的相同内存同步语义:

  • 成功的 lock 操作与成功的 monitorEnter 操作类似
  • 而成功的 unlock 操作则与成功的 monitorExit 操作类似

不成功的锁定与取消锁定操作以及重入锁定/取消锁定操作都不需要任何内存同步效果

3. JDK1.5 中提供了多线程升级解决方案。

.将同步Synchronized替换成现实Lock操作。

Object中的waitnotify notifyAll,替换了Condition对象。

该对象可以Lock进行获取。

该示例中,实现了本方只唤醒对方操作。

 

Lock:替代了Synchronized

    lock

    unlock

    newCondition()

 

Condition:替代了Object wait notify notifyAll

    await();

    signal();

    signalAll();

Example

 

import java.util.concurrent.locks.*;

 

class univer

{

    public static void main(String[] args)

    {

       Resource r = new Resource();

 

       Producer pro = new Producer(r);

       Consumer con = new Consumer(r);

 

       Thread t1 = new Thread(pro);

       Thread t2 = new Thread(pro);

       Thread t3 = new Thread(con);

       Thread t4 = new Thread(con);

 

       t1.start();

       t2.start();

       t3.start();

       t4.start();

 

    }

}

 

class Resource

{

    private Stringname;

    private int count = 1;

    private boolean flag = false;

private Lock lock = new ReentrantLock();①

          

    private Conditioncondition_pro =lock.newCondition();

    private Conditioncondition_con =lock.newCondition();

 

 

 

    public  void set(String name)throwsInterruptedException

    {

lock.lock();③

              try

       {

while(flag)④

 

 

condition_pro.await();

                                    this.name = name+"--"+count++;

 

           System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);

           flag = true;

    condition_con.signal();⑥

              }

       finally

p{

           lock.unlock();//释放锁的动作一定要执行。

       }

      

    }

 

 

    // t3   t4 

    public  void out()throwsInterruptedException

    {

       lock.lock();

       try

       {

           while(!flag)

              condition_con.await();

           System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);

           flag = false;

           condition_pro.signal();

       }

       finally

       {

           lock.unlock();

       }

      

    }

}

 

class Producerimplements Runnable

{

    private Resourceres;

 

    Producer(Resource res)

    {

       this.res = res;

    }

    public void run()

    {

       while(true)

       {

           try

           {

              res.set("+商品+");

           }

           catch (InterruptedException e)

           {

           }

          

       }

    }

}

 

class Consumerimplements Runnable

{

    private Resourceres;

 

    Consumer(Resource res)

    {

       this.res = res;

    }

    public void run()

    {

       while(true)

       {

           try

           {

              res.out();

           }

           catch (InterruptedException e)

           {

           }

       }

    }

}

 

这个程序详细说明了java.util.concurrent.locks 中Lock锁和Condition接口之间的关系。按程序标注做一个说明:

 

①.      Private Lock lock = new ReenTrantLock();

u。首先说明一下Lock:为java.util.concurrent.locks接口 Lock.

Lock实现了比synchronized方法更为灵活的同步方式,它是使线程获取一个锁,每次只能有一个线程获取锁,其他线程只能等待,直到unlock()方法释放锁后,其他线程才可以获取执行权。

v。New ReentrantLock():ReentrantrantLock是一个java.util.concurrent.locks包中的类,继承关系为:
java.lang.Object  -----java.util.concurrent.locks.ReentrantLock。
public class ReentrantLock extends Object implements Lock, Serializable
w。注意:此类中有继承于接口中的方法:Lock(),unlock()等方法。而获取锁的语句就是①所写,private Lock lock = new ReentrantLock();通过ReentrantLock类构造函数,创建一个ReentrantLock实例,并赋值给接口Lock类的lock对象,从而获取锁。

②.private Condition condition_pro= lock.newCondition();

   private Condition condition_con = lock.newCondition();
这个condition在这综合了notify,notifyAll等的功能。
下面做一个详细说明:
u。Condition是java.util.concurrent.locks包中类所实现的接口。
    public interface Condition。
v。接口中方法await()造成当前线程在接到信号或被中断之前一直处于等待状态。,signal()唤醒一个等待线程,signalAll()唤醒所有的线程。当然这些方法在它所实现的类中实现。
w。Condition 将 Object 监视器方法(waitnotify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set (wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。
条件(也称为条件队列 或条件变量)为线程提供了一个含义,以便在某个状态条件现在可能为 true 的另一个线程通知它之前,一直挂起该线程(即让其“等待”)。因为访问此共享状态信息发生在不同的线程中,所以它必须受保护,因此要将某种形式的锁定与该条件相关联。等待提供一个条件的主要属性是:以原子方式 释放相关的锁定,并挂起当前线程,就像 Object.wait 做的那样。
Condition 实例实质上被绑定到一个锁定上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。
作为一个示例,假定有一个绑定的缓冲区,它支持 put 和 take 方法。如果试图在空的缓冲区上执行 take 操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put 操作,则在有空间变得可用之前,线程将一直阻塞。我们喜欢在单独的等待 set 中保存 put 线程和 take 线程,这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程。可以使用两个 Condition实例来做到这一点。
Example:Condition与Lock使用的标准模板:
class BoundedBuffer {
   final Lock lock = new ReentrantLock();
   final Condition notFull  = lock.newCondition(); 
   final Condition notEmpty = lock.newCondition(); 
 
   final Object[] items = new Object[100];
   int putptr, takeptr, count;
 
   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length) 
         notFull.await();
       items[putptr] = x; 
       if (++putptr == items.length) putptr = 0;
       ++count;
       notEmpty.signal();
     } finally {
       lock.unlock();
     }
   }
 
   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0) 
         notEmpty.await();
       Object x = items[takeptr]; 
       if (++takeptr == items.length) takeptr = 0;
       --count;
       notFull.signal();
       return x;
     } finally {
       lock.unlock();
     }
   } 
 }
x。newCondition()方法:newCondition()方法是定义在Lock接口中的方法,它的作用是:返回绑定到此 Lock 实例的新 Condition 实例。
故通过Lock对象lock来调用newCondition()方法来返回一个condition实例,
并把这个返回的对象赋给Condition的对象,以便用于调用Condition中的await(),signal(),signalAll()等方法,调用方式为:
final Condition notFull  = lock.newCondition(); 
final Condition notEmpty = lock.newCondition(); 
notFull.await();notFull.signal(),notFull.signalAll();
notEmpty.await();notEmpty.signal(),notEmpty.signalAll();
 
③.lock.lock();
   u.前面一个lock为接口类Lock的一个对象,后一个lock为接口Lock中的lock方法,用于获取锁定。
   v.这个语句与后面lock.unlock()同理。
④.While(flag):

       While在这个起一个循环的作用,但是在这如果把语句换成:if(flag)

                                                                                                     condition_pro.await();
我认为与while的效果一样。原因是:在第一个分号while语句结束:如果flag为true,那么获取锁的线程将会等待。如果flag为假,那么此线程将不会等待,它将会跳过语句condition_pro.await();继续执行下去。
故而从这而开来,while循环用在这和使用if的作用一样。

⑤.condition_pro.await();

u。void await() throws InterruptedException:此方法为接口condition中的方法;

此 Condition 相关的锁定被原子地释放,并且出于线程调度的目的,将禁用当前线程,且在发生以下四种情况之一 以前,当前线程将一直处于休眠状态:

  • 其他某个线程调用此 Condition 的 signal() 方法,并且碰巧将当前线程选为被唤醒的线程;或者
  • 其他某个线程调用此 Condition 的 signalAll() 方法;或者
  • 其他某个线程中断当前线程,且支持中断线程的挂起;或者
  • 发生“虚假唤醒”

在所有情况下,在此方法可以返回当前线程之前,都必须重新获取与此条件有关的锁定。在线程返回时,可以保证 它保持此锁定。

如果当前线程:

  • 在进入此方法时已经设置了该线程的中断状态;或者
  • 在支持等待和中断线程挂起时,线程被中断
则抛出 InterruptedException,并清除当前线程的中断状态。在第一种情况下,没有指定是否在释放锁定之前发生中断测试。

v.由于await方法抛出了异常,所以在使用此方法时必须try{}catch(){}finally{};

如果在程序中不用catch(){}处理异常,那么在函数尾部必须显示的申明抛出:

例如:public Object take() throws InterruptedException

⑥.condition_con.signal();

这条语句就是单纯的使用接口Condition对象condition_con对接口中的函数signal()进行调用,其作用是:唤醒线程池中某个线程。

7. lock.unlock();

该语句将释放锁,让其他线程有机会获取此锁,释放锁的操作是必须进行的,是释放资源的操作,故放在finally代码块中。

 

 ------- android培训java培训、期待与您交流! ----------

  详情请查看:http://edu.csdn.net/heima

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值