黑马程序员技术交流社区

标题: 多线程 synchronized 与 lock [打印本页]

作者: 于海龙    时间: 2013-5-2 09:50
标题: 多线程 synchronized 与 lock
本帖最后由 于海龙 于 2013-5-3 09:29 编辑

两者有什么区别,  如何选择使用。
作者: harborbest    时间: 2013-5-2 10:01
synchronized有两种用法,一种是在方法定义时使用,多线程状态下,这个方法只能同时被同一个线程执行;另一种用于锁定代码段,也就是说,{ }括号中的代码是不会同时被多个线程执行,而是排队执行。
线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定,
如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断
如果 使用Lock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情
synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中


作者: 刘学明       时间: 2013-5-2 10:23
本帖最后由 刘学明    于 2013-5-2 10:25 编辑

首先 Lock是 JDK1.5版本后的新特性   
Lock替代了synchronized
Condition对象替代了锁对象

一:代码层的区别:
  1. public void method(){
  2.     synchronized(this){ //旧锁 ,无需人工释放  
  3.           try(this.wait()}catch(Exception e){}
  4.           System.out.println();
  5.                this.notifyAll();
  6.         }
  7. }


  8. public void method2(){
  9.      Lock lock = new ReentrantLock();
  10.      Condition condition  = lock.newCondition();
  11.      lock.lock();//上锁
  12.    try{
  13.             try{condition.await();}catch(Exception e){}
  14.             System.out.println("..");
  15.              condition.signalAll();
  16.      }finally{
  17.                lock.unlock();
  18.               }
  19. }


复制代码
在高并发时,Lock性能 优势很明显  ,在低并发时,synchronized也能取得优势 。
代码示例:
  1. lass Resource
  2. {
  3.         private String name;
  4.         private int count = 1;
  5.         private boolean flag = false;
  6.                         //  t1    t2
  7.         private Lock lock = new ReentrantLock();

  8.         private Condition condition_pro = lock.newCondition();  //当多线程并发时 使用Lock机制可以创建两个Condition对象
  9.         private Condition condition_con = lock.newCondition();



  10.         public  void set(String name)throws InterruptedException
  11.         {
  12.                 lock.lock();
  13.                 try
  14.                 {
  15.                         while(flag)
  16.                                 condition_pro.await();//t1,t2  //冻结生产方
  17.                         this.name = name+"--"+count++;

  18.                         System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
  19.                         flag = true;
  20.                         condition_con.signal();// 可以只唤醒消费方,而没有唤醒生产方
  21.                 }
  22.                 finally
  23.                 {
  24.                         lock.unlock();//释放锁的动作一定要执行。
  25.                 }
  26.         }


  27.         //  t3   t4  
  28.         public  void out()throws InterruptedException
  29.         {
  30.                 lock.lock();
  31.                 try
  32.                 {
  33.                         while(!flag)
  34.                                 condition_con.await();//冻结消费方
  35.                         System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
  36.                         flag = false;
  37.                         condition_pro.signal(); //只唤醒生产方 没唤醒消费方
  38.                 }
  39.                 finally
  40.                 {
  41.                         lock.unlock();
  42.                 }
  43.                
  44.         }
  45. }

  46. class Producer implements Runnable
  47. {
  48.         private Resource res;

  49.         Producer(Resource res)
  50.         {
  51.                 this.res = res;
  52.         }
  53.         public void run()
  54.         {
  55.                 while(true)
  56.                 {
  57.                         try
  58.                         {
  59.                                 res.set("+商品+");
  60.                         }
  61.                         catch (InterruptedException e)
  62.                         {
  63.                         }
  64.                         
  65.                 }
  66.         }
  67. }

  68. class Consumer implements Runnable
  69. {
  70.         private Resource res;

  71.         Consumer(Resource res)
  72.         {
  73.                 this.res = res;
  74.         }
  75.         public void run()
  76.         {
  77.                 while(true)
  78.                 {
  79.                         try
  80.                         {
  81.                                 res.out();
  82.                         }
  83.                         catch (InterruptedException e)
  84.                         {
  85.                         }
  86.                 }
  87.         }
  88. }
复制代码
综合来看,对于所有的高并发情况,采用Lock加锁是最优选择, 但是由于历史遗留等问题 synchronized也还是不能完全淘汰 同时 在低并发的情况下,synchronized的性能还是比Lock要好的
作者: 刘胜寒    时间: 2013-5-2 10:42
受教了...
作者: 余雷    时间: 2013-5-2 11:30
主要相同点:Lock能完成Synchronized所实现的所有功能。
主要不同点:Lock有比Synchronized更精确的县城予以和更好的性能。Synchronized会自动释放锁,但是Lock一定要求程序员手工释放,并且必须在finally从句中释放。
synchronized 修饰方法时 表示同一个对象在不同的线程中 表现为同步队列
如果实例化不同的对象 那么synchronized就不会出现同步效果了。
1.对象的锁
所有对象都自动含有单一的锁。
JVM负责跟踪对象被加锁的次数。如果一个对象被解锁,其计数变为0。在任务(线程)第一次给对象加锁的时候,计数变为1。每当这个相同的任务(线程)在此对象上获得锁时,计数会递增。
只有首先获得锁的任务(线程)才能继续获取该对象上的多个锁。
每当任务离开一个synchronized方法,计数递减,当计数为0的时候,锁被完全释放,此时别的任务就可以使用此资源。
2.synchronized同步块
2.1同步到单一对象锁
当使用同步块时,如果方法下的同步块都同步到一个对象上的锁,则所有的任务(线程)只能互斥的进入这些同步块。
Resource1.java演示了三个线程(包括main线程)试图进入某个类的三个不同的方法的同步块中,虽然这些同步块处在不同的方法中,但由于是同步到同一个对象(当前对象 synchronized (this)),所以对它们的方法依然是互斥的。
比如
Class Test
{
    public static User user=null;
    Public synchronized void add(User u)
{
     user=u;
     Dao.save(user)
}
}
如果在线程1中 Test test=new Test();
User u=new User();
u.setUserName(“liaomin”);
u.setUserPassword(“liaomin”);
                Test.add(u);
如果在线程2中 Test tes1t=new Test();
User u1=new User();
u1.setUserName(“huqun”);
u1.setUserPassword(“huqun”);
                Tes1t.add(u1);
那么 现在线程1 和线程2同时启动 如果对象new的不是同一个Test
那么出现线程交叉的话 那么插入数据库中的数据就是相同的
因为你的user变量时静态的   你给他赋值第一次 假如还没有save的时候
另外一个线程改变了user的值 那么第一个线程插入时也就是第二次赋予的值了
所以要实现同步 那么可以改方法为静态的就能达到同步的效果了
修改如下
Public static synchronized void add(User u)
{
     user=u;
     Dao.save(user)
}
修改为static的方法是存在于堆中
是全局方法 针对于所有实例化与未 实例化的对象只存在一个 所以会出现同步队列
当然不用static 也可以 那就用lock
Class Test
{
public static User user=null;
Lock lock=new ReentrantLock();
      Public void add(User u)
{
lock.lock();
     user=u;
     Dao.save(user);
lock.unlock();
}
}
这样无论你new多少个对象都会是线程同步的
相当于
Public static synchronized void add(User u)
{
   user=u;
     Dao.save(user)
}
同时 lock性能上高于synchronized
只是lock需要手动关闭






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2