synchronized和ReentrantLock区别浅析

来源:互联网 发布:java迭代器中数组赋值 编辑:程序博客网 时间:2024/06/06 14:13

一、什么是sychronized

       sychronized是java中最基本同步互斥的手段,可以修饰代码块,方法,类.

      在修饰代码块的时候需要一个reference对象作为锁的对象.

      在修饰方法的时候默认是当前对象作为锁的对象.

      在修饰类时候默认是当前类的Class对象作为锁的对象.

      synchronized会在进入同步块的前后分别形成monitorenter和monitorexit字节码指令.在执行monitorenter指令时会尝试获取对象的锁,如果此没对象没有被锁,或者此对象已经被当前线程锁住,那么锁的计数器加一,每当monitorexit被锁的对象的计数器减一.直到为0就释放该对象的锁.由此synchronized是可重入的,不会出现自己把自己锁死.

二、什么ReentrantLock(可重入锁)

      以对象的方式来操作对象锁.相对于sychronized需要在finally中去释放锁。

 

三、synchronized和ReentrantLock的区别

     1. 等待可中断

     在持有锁的线程长时间不释放锁的时候,等待的线程可以选择放弃等待.   tryLock(long timeout, TimeUnit unit)。

     ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了 锁投票,定时锁等候和中断锁等候。

 线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定。

  如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断。

  如果使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情。

  ReentrantLock获取锁定与三种方式: 
        a)  lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁

    b) tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;

    c) tryLock (long timeout, TimeUnit  unit),   如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;

    d) lockInterruptibly: 如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断

    2.公平锁与非公平锁

        按照申请锁的顺序来一次获得锁称为公平锁.synchronized的是非公平锁,ReentrantLock可以通过构造函数实现公平锁.    new RenentrantLock(boolean fair)

        3.绑定多个Condition

        通过多次newCondition可以获得多个Condition对象,可以简单的实现比较复杂的线程同步的功能.通过await(),signal()

        此外,synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将 unLock()放到finally{} 中。在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态。

四、实例演示

      ReentrantLock 的lock机制有2种,忽略中断锁和响应中断锁,这给我们带来了很大的灵活性。比如:如果A、B两个线程去竞争锁,A线程得到了锁,B线程等待,但是A线程这个时候实在有太多事情要处理,就是一直不返回,B线程可能就会等不及了,想中断自己,不再等待这个锁了,转而处理其他事情。这个时候ReentrantLock就提供了两种机制:

       一、B线程中断自己(或者别的线程中断它),但ReentrantLock 不去响应,让B线程继续等待,你再怎么中断,我全当耳边风(synchronized原语就是如此);

       二、B线程中断自己(或者别的线程中断它),ReentrantLock 处理了这个中断,并且不再等待这个锁的到来,完全放弃。

      请看例子:

[html] view plain copy
  1. package zmx.multithread.test.reentrantlock;  
  2.   
  3. import java.util.concurrent.locks.ReentrantLock;  
  4.   
  5.   
  6. /**  
  7.  *   
  8.  * @author zhangwenchao  
  9.  *  
  10.  */  
  11.   
  12. public class ReentrantLockTest {  
  13.     //是用ReentrantLock,还是用synchronized  
  14.       
  15.     public static boolean useSynchronized = false;  
  16.       
  17.     public static void main(String[] args) {  
  18.         IBuffer buff = null;  
  19.         if(useSynchronized){  
  20.             buff = new Buffer();  
  21.         }else{  
  22.             buff = new BufferInterruptibly();      
  23.         }  
  24.         final Writer writer = new Writer(buff);  
  25.         final Reader reader = new Reader(buff);  
  26.         writer.start();  
  27.         reader.start();  
  28.         new Thread(new Runnable() {  
  29.             public void run() {  
  30.                 long start = System.currentTimeMillis();  
  31.                 for (;;) {  
  32.                     // 等5秒钟去中断读  
  33.                     if (System.currentTimeMillis() - start > 5000) {  
  34.                         System.out.println("不等了,尝试中断");  
  35.                         reader.interrupt();  
  36.                         break;  
  37.                     }  
  38.   
  39.                 }  
  40.   
  41.             }  
  42.         }).start();  
  43.     }  
  44. }  
  45.   
  46. interface IBuffer{  
  47.     public void write();  
  48.     public void read() throws InterruptedException;  
  49. }  
  50.   
  51. class Buffer implements IBuffer{  
  52.     private Object lock;  
  53.   
  54.     public Buffer() {  
  55.         lock = this;  
  56.     }  
  57.   
  58.     public void write() {  
  59.         synchronized (lock) {  
  60.             long startTime = System.currentTimeMillis();  
  61.             System.out.println("开始往这个buff写入数据…");  
  62.             for (;;)// 模拟要处理很长时间  
  63.             {  
  64.                 if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE)  
  65.                     break;  
  66.             }  
  67.             System.out.println("终于写完了");  
  68.         }  
  69.     }  
  70.   
  71.     public void read() {  
  72.         synchronized (lock) {  
  73.             System.out.println("从这个buff读数据");  
  74.         }  
  75.     }  
  76. }  
  77.   
  78. class BufferInterruptibly implements IBuffer{  
  79.   
  80.     private ReentrantLock lock = new ReentrantLock();  
  81.   
  82.     public void write() {  
  83.         lock.lock();  
  84.         try {  
  85.             long startTime = System.currentTimeMillis();  
  86.             System.out.println("开始往这个buff写入数据…");  
  87.             for (;;)// 模拟要处理很长时间  
  88.             {  
  89.                 if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE)  
  90.                     break;  
  91.             }  
  92.             System.out.println("终于写完了");  
  93.         } finally {  
  94.             lock.unlock();  
  95.         }  
  96.     }  
  97.   
  98.     public void read() throws InterruptedException{  
  99.         lock.lockInterruptibly();// 注意这里,可以响应中断  
  100.        // lock.lock();// 注意这里,不可以响应中断  
  101.         try {  
  102.             System.out.println("从这个buff读数据");  
  103.         } finally {  
  104.             lock.unlock();  
  105.         }  
  106.     }  
  107.   
  108. }  
  109.   
  110. class Writer extends Thread {  
  111.   
  112.     private IBuffer buff;  
  113.   
  114.     public Writer(IBuffer buff) {  
  115.         this.buff = buff;  
  116.     }  
  117.   
  118.     @Override  
  119.     public void run() {  
  120.         buff.write();  
  121.     }  
  122.   
  123. }  
  124.   
  125. class Reader extends Thread {  
  126.   
  127.     private IBuffer buff;  
  128.   
  129.     public Reader(IBuffer buff) {  
  130.         this.buff = buff;  
  131.     }  
  132.   
  133.     @Override  
  134.     public void run() {  
  135.   
  136.         try {  
  137.             buff.read();  
  138.         } catch (InterruptedException e) {  
  139.             System.out.println("我不读了");     
  140.         }  
  141.   
  142.         System.out.println("读结束");  
  143.   
  144.     }  
  145. }  


 

      1) 如果使用lock.lockInterruptibly();指定可以响应中断,则输出如下:

[html] view plain copy
  1. 开始往这个buff写入数据…  
  2. 不等了,尝试中断  
  3. 我不读了  
  4. 读结束  

      则:获取到中断异常,执行中断异常处理程序。

     2) 如果使用lock.lock();指定不可以响应中断,则输出如下:

[html] view plain copy
  1. 开始往这个buff写入数据…  
  2. 不等了,尝试中断  

     则:不能获取到中断异常,线程等待。

    示例二:

[html] view plain copy
  1. package zmx.multithread.test.reentrantlock;  
  2.   
  3. import java.util.concurrent.TimeUnit;    
  4. import java.util.concurrent.locks.Lock;    
  5. import java.util.concurrent.locks.ReentrantLock;    
  6.     
  7. public class T2{    
  8.     public static void main(String[] args){      
  9.         Thread i1 = new Thread(new RunIt3());    
  10.         Thread i2 = new Thread(new RunIt3());    
  11.         i1.start();    
  12.         i2.start();    
  13.         i2.interrupt();  //中断  
  14.     }    
  15.   }    
  16.    
  17. class RunIt3 implements Runnable{    
  18.     
  19.     private static Lock lock = new ReentrantLock();    
  20.     public void run(){    
  21.         try{    
  22.             //---------a--------------------------    
  23.             //lock.lock();              
  24.             lock.lockInterruptibly();   
  25.             //lock.tryLock();  
  26.             //lock.tryLock(5,TimeUnit.SECONDS);   
  27.             System.out.println(Thread.currentThread().getName() + " running");    
  28.             TimeUnit.SECONDS.sleep(10);               
  29.             System.out.println(Thread.currentThread().getName() + " finished");   
  30.             lock.unlock();  
  31.               
  32.         }catch (InterruptedException e){    
  33.             System.out.println(Thread.currentThread().getName() + " interrupted");    
  34.     
  35.         }    
  36.     
  37.     }    
  38. }   


    如果a处是lock.lock(); 输出: 
Thread-0 running 
(这里休眠了10s) 
Thread-0 finished 
Thread-1 running 
Thread-1 interrupted 
============================ 
    如果a处是lock.lockInterruptibly();输出: 
Thread-0 running 
Thread-1 interrupted 
(这里休眠了10s) 
Thread-0 finished 

原创粉丝点击