多线程学习笔记(六)之锁对象Lock 一时失言乱红尘 2022-06-16 04:40 325阅读 0赞 # 接口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...//access the resource protected by this lock }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();//根据锁对象lock获取一组监视器对象 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; //notifyAll(); 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; //notifyAll(); 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][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; //notifyAll(); 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; //notifyAll(); 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(); } } [http_blog.csdn.net_megustas_jjc_article_details_71107387]: http://blog.csdn.net/megustas_jjc/article/details/71107387
还没有评论,来说两句吧...