A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© ς高眼光の目标 中级黑马   /  2014-5-2 05:14  /  807 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

lock和synchronized有什么区别?
我感觉用起来都一样 lock没什么突出的地方

3 个回复

正序浏览
以生产者消费者的那个例子解释的话就是, 使用synchronized的话, 你把生产者线程等待后你想要唤醒消费者其他线程, 这时候你只能唤醒其他所有的线程才可以, 万一你唤醒的还是生产者线程呢? 程序就会挂掉的哦

其实吧, Lock替代了synchronized方法和语句, 同时功能更加强大, 不然Lock的出现没有任何意义, Condition替代了Object监视器的方法, 同时功能更加强大, 好处就是释放线程的时候可以选择只释放对方线程, 这样写起来绝对会很爽的哦

为什么呢? 还是生产者消费者的那个例子, 使用 synchronized 的话, 如果想唤醒对方线程, 只有一种方法, 使用notifyAll() 唤醒其他所有线程,否则可能全部等待, 而使用 Lock + Condition的话, 你就可以选择只释放对方线程的

使用 synchronized 的代码
  1. class Goods {
  2.         private String name; private int count = 1;
  3.         private boolean flag = false;

  4.         public synchronized void set(String name) {
  5.                
  6.                 while (flag)// 如果用if()循环,操作set的进程就只能有一个
  7.                         try {
  8.                                 this.wait();// 因为等待在这里的其他操作set的线程不会再判断条件
  9.                         } catch (InterruptedException e) {}
  10.                 this.name = name + "--" + count++;
  11.                 System.out.println("生产者--" + this.name);
  12.                 flag = true;
  13.                 this.notifyAll();// notifyAll():唤醒其他所有线程,否则可能全部等待
  14.         }

  15.         public synchronized void out() {
  16.                 while (!flag)// 让被唤醒的线程再一次判断标记
  17.                         try {
  18.                                 this.wait();// wait()冻结当前线程,只能try,不能抛
  19.                         } catch (InterruptedException e) {}
  20.                 System.out.println("消费者----"+ this.name);
  21.                 flag = false;
  22.                 this.notifyAll();// 因为如果用notify(),可能会只唤醒了本方线程
  23.         }
  24. }

  25. class Producer implements Runnable {
  26.         private Goods g; Producer(Goods g) {this.g = g;}
  27.         public void run() { while (true) { g.set("商品"); }}}

  28. class Consumer implements Runnable {
  29.         private Goods g; Consumer(Goods g) {this.g = g;}
  30.         public void run() { while (true) { g.out(); }}}

  31. public class SunJingQi {
  32.         public static void main(String[] args) { Goods g = new Goods();
  33.                 new Thread(new Producer(g)).start();
  34.                 new Thread(new Producer(g)).start();
  35.                 new Thread(new Consumer(g)).start();
  36.                 new Thread(new Consumer(g)).start();
  37. }}
复制代码



使用Lock的代码
  1. import java.util.concurrent.locks.Condition;
  2. import java.util.concurrent.locks.Lock;
  3. import java.util.concurrent.locks.ReentrantLock;

  4. class Goods {
  5.         private String name;
  6.         private int count = 1;
  7.         private boolean flag = false;
  8.         // Lock替代了synchronized方法和语句,Condition替代了Object监视器的方法
  9.         private Lock lock = new ReentrantLock();
  10.         private Condition condition_pro = lock.newCondition();
  11.         private Condition condition_con = lock.newCondition();

  12.         public void set(String name) throws InterruptedException {

  13.                 lock.lock();
  14.                 try {
  15.                         while (flag)
  16.                                 condition_pro.await();
  17.                         this.name = name + "--" + count++;
  18.                         System.out.println("生产者--" + this.name);
  19.                         flag = true;
  20.                         condition_con.signal();// 只唤醒对方线程
  21.                 } finally {
  22.                         lock.unlock();
  23.                 }
  24.         }

  25.         public void out() throws InterruptedException {

  26.                 lock.lock();
  27.                 try {
  28.                         while (!flag)
  29.                                 condition_con.await();
  30.                         System.out.println("消费者----" + this.name);
  31.                         flag = false;
  32.                         condition_pro.signal();// 只唤醒对方线程
  33.                 } finally {
  34.                         lock.unlock();
  35.                 }
  36.         }
  37. }
复制代码

评分

参与人数 1技术分 +1 收起 理由
zzkang0206 + 1

查看全部评分

回复 使用道具 举报
Lock接口:多线程在JDK1.5版本升级时,推出一个接口Lock接口。
解决线程安全问题使用同步的形式,(同步代码块,要么同步函数)其实最终使用的都是锁机制。

到了后期版本,直接将锁封装成了对象。线程进入同步就是具备了锁,执行完,离开同步,就是释放了锁。
在后期对锁的分析过程中,发现,获取锁,或者释放锁的动作应该是锁这个事物更清楚。所以将这些动作定义在了锁当中,并把锁定义成对象。

所以同步是隐示的锁操作,而Lock对象是显示的锁操作,它的出现就替代了同步。

在之前的版本中使用Object类中wait、notify、notifyAll的方式来完成的。那是因为同步中的锁是任意对象,所以操作锁的等待唤醒的方法都定义在Object类中。

而现在锁是指定对象Lock。所以查找等待唤醒机制方式需要通过Lock接口来完成。而Lock接口中并没有直接操作等待唤醒的方法,而是将这些方式又单独封装到了一个对象中。这个对象就是Condition,将Object中的三个方法进行单独的封装。并提供了功能一致的方法 await()、signal()、signalAll()体现新版本对象的好处。
< java.util.concurrent.locks > Condition接口:await()、signal()、signalAll();
  1. class BoundedBuffer {
  2.    final Lock lock = new ReentrantLock();
  3.    final Condition notFull  = lock.newCondition();
  4.    final Condition notEmpty = lock.newCondition();
  5.    final Object[] items = new Object[100];
  6.    int putptr, takeptr, count;
  7.    public void put(Object x) throws InterruptedException {
  8.      lock.lock();
  9.      try {
  10.        while (count == items.length)
  11.          notFull.await();
  12.        items[putptr] = x;
  13.        if (++putptr == items.length) putptr = 0;
  14.        ++count;
  15.        notEmpty.signal();
  16.      }
  17.         finally {
  18.        lock.unlock();
  19.      }
  20.    }
  21.    public Object take() throws InterruptedException {
  22.      lock.lock();
  23.      try {
  24.        while (count == 0)
  25.          notEmpty.await();
  26.        Object x = items[takeptr];
  27.        if (++takeptr == items.length) takeptr = 0;
  28.        --count;
  29.        notFull.signal();
  30.        return x;
  31.      }
  32.    finally {
  33.        lock.unlock();
  34.      }
  35.    }
  36. }
复制代码

评分

参与人数 1技术分 +1 收起 理由
菜小徐 + 1

查看全部评分

回复 使用道具 举报
本帖最后由 张然龙 于 2014-5-2 08:51 编辑

我想说你肯定还没弄清楚 Condition这个类是用来干嘛的。。

Lock这个类与synchronized这个类没有本质上的区别,  但是作为1.5出现的新特性必然有着他的优势,我跟你说一下:

如果出现三个线程或者三个线程以在同一个zynchronized中的情况时,你想用notify方法唤醒的是随机的线程,这个是随机无法控制的。


就像老师生产商品的举例一样,当只有一个出售的线程是运行状态,其他线程挂起,如果notify唤醒的出售线程的话,那么势必就会出现一个商品出售两次的现象!这就导致程序的运行顺序错误!而synchronized也可以解决这个问题:将 if语句修改为while这样只要唤醒的是本方一样会被冻结,这就出现了多次判断!而为了防止所有的线程都进入冻结状态,所以notify方法不能只唤醒单一一个线程,所以应修改为notifyAll方法。

而Lock方法不一样,它内部是可以定义Condition这个类的,他自身定义了一些独有的方法用来操作多线程,Condition的作用你可以参考我以前发的一个帖子。


   代码如下↓


  1. /*
  2. 下面的代码中有两个对象
  3. Condition con1=lo.newCondition();//con1是指哪些线程?  如何区分?
  4. Condition con2=lo.newCondition();//con2是指哪些线程?  如何区分?
  5. 如注释所示,  如何进行区分?con1.await()到底停下的是哪些线程?
  6. con1.signal()到底开启的是哪些线程?
  7. */

  8. import java.util.concurrent.locks.*;
  9. class Start
  10. {
  11.         boolean flag=true;
  12.         int x;
  13.         Lock lo=new ReentrantLock();
  14.         Condition con1=lo.newCondition();//con1是指哪些线程?  如何区分?
  15.         Condition con2=lo.newCondition();//con2是指哪些线程?  如何区分?
  16.         public void kaishi()
  17.         {
  18.                 while(true)
  19.                 {
  20.                         lo.lock();
  21.                         while(!flag)
  22.                         {
  23.                                 try {con1.await();} catch (InterruptedException e) {e.printStackTrace();}
  24.                         }
  25.                         System.out.println("开始  " +x++);
  26.                         flag=false;
  27.                         con2.signal();
  28.                         lo.unlock();
  29.                 }
  30.         }
  31.         public void jieshu()
  32.         {
  33.                 while (true)
  34.                 {
  35.                         
  36.                         lo.lock();
  37.                         while(flag)
  38.                         {
  39.                                 try {con2.await();} catch (InterruptedException e) {e.printStackTrace();}
  40.                         }
  41.                         System.out.println("结束----" +x);
  42.                         flag=true;
  43.                         con1.signal();
  44.                         lo.unlock();
  45.                 }
  46.                
  47.         }
  48. }
  49. class A implements Runnable
  50. {
  51.         Start huan;
  52.         A(Start a)
  53.         {
  54.                 this.huan=a;
  55.         }
  56.         public void run()
  57.         {
  58.                 huan.kaishi();
  59.         }
  60. }
  61. class B implements Runnable
  62. {
  63.         Start huan;
  64.         B(Start a)
  65.         {
  66.                 this.huan=a;
  67.         }
  68.         public void run()
  69.         {
  70.                 huan.jieshu();
  71.         }
  72. }



  73. class Demo2
  74. {
  75.         public static void main(String args[])
  76.         {
  77.                 Start s=new Start();
  78.                 new Thread(new A(s)).start();
  79.                 new Thread(new A(s)).start();
  80.                 new Thread(new B(s)).start();
  81.                 new Thread(new B(s)).start();
  82.         }
  83. }
复制代码


因为有四个线程,当第一个线程挂在con1.await();时挂起释放执行权进入冻结状态 ,如果其他线程读到con1.signal();自动将挂在con1.await();的线程唤醒。
如果有多个同时挂起在con1.await();的线程,则随机唤醒一个。同理 con2的对象也是一样。上边的线程生产商品冻结con1,唤醒con2,下边的的线程生产商品冻结con2,唤醒con1,正好实现了互相交替、互不影响的局面!
这就是Lock 与Condition互相搭配的作用


我也是刚才几天学会的多线程,已经把所有的知识点吃透了,所以给你介绍了一遍,有不会的可以加好友探讨下!








评分

参与人数 1技术分 +1 收起 理由
轻语。 + 1

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马