zoukankan      html  css  js  c++  java
  • 55 synchronized 和 ReentrantLock 区别是什么?

    synchronized 和 ReentrantLock 区别是什么?

    答:

    主要区别如下:

    1. ReentrantLock 只适用于代码块锁,而 synchronized 可用于修饰方法、代码块等。

    2. synchronized 竞争锁时会一直等待;ReentrantLock 可以尝试获取锁,并得到获取结果

    3. 超时获取锁的特性:synchronized 获取锁无法设置超时;ReentrantLock 可以设置获取锁的超时时间

    4. synchronized 无法实现公平锁;ReentrantLock 可以满足公平锁,即先等待先获取到锁

    5. synchronized 控制等待和唤醒需要结合加锁对象的 wait() 和 notify()、notifyAll();ReentrantLock 控制等待和唤醒需要结合 Condition 的 await() 和 signal()、signalAll() 方法

    6. synchronized 是 JVM 层面实现的;ReentrantLock 是 JDK 代码层面实现

    7. 便利性:synchronized 在加锁代码块执行完或者出现异常,自动释放锁;ReentrantLock 不会自动释放锁,需要手动在 finally{} 代码块显示释放

    相同点:都可以做到同一线程,同一把锁,可重入代码块。

    原文链接: https://www.cnblogs.com/ConstXiong/p/12014904.html (概念)
    原文链接: https://www.cnblogs.com/jlutiger/p/10548291.html (底层原理)
    原文链接: https://blog.csdn.net/zmx729618/article/details/51594166 (代码示例演示)

    拓展:

    ReentrantLock称为重入锁,位于JUC包的locks,和CountDownLatch、FutureTask一样基于AQS实现。能够实现比synchronized更细粒度的控制,比如控制公平性。此外需要注意,调用lock()之后,必须调用unlock()释放锁。它的性能未必比synchronized高,并且是可重入的。

    在Java 6之后,synchronized性能得到很大提升。主要是因为引入了:

      1:Adaptive spinning(自适应自旋)

      2:Lock Eliminate(锁消除)

      3:Lock Coarsening(锁粗化)

      4:Lightweight Locking(轻量级锁)

      5:Biased Locking(偏向锁)

      6:......

    公平锁与非公平锁

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

    实例演示

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

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

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

    请看例子:

    package zmx.multithread.test.reentrantlock;
     
    import java.util.concurrent.locks.ReentrantLock;
     
     
    /**
     * 
     * @author zhangwenchao
     *
     */
     
    public class ReentrantLockTest {
        //是用ReentrantLock,还是用synchronized
    	
        public static boolean useSynchronized = false;
        
        public static void main(String[] args) {
            IBuffer buff = null;
            if(useSynchronized){
                buff = new Buffer();
            }else{
                buff = new BufferInterruptibly();    
            }
            final Writer writer = new Writer(buff);
            final Reader reader = new Reader(buff);
            writer.start();
            reader.start();
            new Thread(new Runnable() {
                public void run() {
                    long start = System.currentTimeMillis();
                    for (;;) {
                        // 等5秒钟去中断读
                        if (System.currentTimeMillis() - start > 5000) {
                            System.out.println("不等了,尝试中断");
                            reader.interrupt();
                            break;
                        }
     
                    }
     
                }
            }).start();
        }
    }
     
    interface IBuffer{
        public void write();
        public void read() throws InterruptedException;
    }
     
    class Buffer implements IBuffer{
        private Object lock;
     
        public Buffer() {
            lock = this;
        }
     
        public void write() {
            synchronized (lock) {
                long startTime = System.currentTimeMillis();
                System.out.println("开始往这个buff写入数据…");
                for (;;)// 模拟要处理很长时间
                {
                    if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE)
                        break;
                }
                System.out.println("终于写完了");
            }
        }
     
        public void read() {
            synchronized (lock) {
                System.out.println("从这个buff读数据");
            }
        }
    }
     
    class BufferInterruptibly implements IBuffer{
     
        private ReentrantLock lock = new ReentrantLock();
     
        public void write() {
            lock.lock();
            try {
                long startTime = System.currentTimeMillis();
                System.out.println("开始往这个buff写入数据…");
                for (;;)// 模拟要处理很长时间
                {
                    if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE)
                        break;
                }
                System.out.println("终于写完了");
            } finally {
                lock.unlock();
            }
        }
     
        public void read() throws InterruptedException{
            lock.lockInterruptibly();// 注意这里,可以响应中断
           // lock.lock();// 注意这里,不可以响应中断
            try {
                System.out.println("从这个buff读数据");
            } finally {
                lock.unlock();
            }
        }
     
    }
     
    class Writer extends Thread {
     
        private IBuffer buff;
     
        public Writer(IBuffer buff) {
            this.buff = buff;
        }
     
        @Override
        public void run() {
            buff.write();
        }
     
    }
     
    class Reader extends Thread {
     
        private IBuffer buff;
     
        public Reader(IBuffer buff) {
            this.buff = buff;
        }
     
        @Override
        public void run() {
     
            try {
                buff.read();
            } catch (InterruptedException e) {
                System.out.println("我不读了");   
            }
     
            System.out.println("读结束");
     
        }
    }
    

     

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

    开始往这个buff写入数据…
    不等了,尝试中断
    我不读了
    读结束`
    

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

    1. 如果使用lock.lock();指定不可以响应中断,则输出如下:
    开始往这个buff写入数据…
    不等了,尝试中断
    

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

    示例二:

    package zmx.multithread.test.reentrantlock;
     
    import java.util.concurrent.TimeUnit;  
    import java.util.concurrent.locks.Lock;  
    import java.util.concurrent.locks.ReentrantLock;  
      
    public class T2{  
        public static void main(String[] args){    
            Thread i1 = new Thread(new RunIt3());  
            Thread i2 = new Thread(new RunIt3());  
            i1.start();  
            i2.start();  
            i2.interrupt();  //中断
        }  
      }  
     
    class RunIt3 implements Runnable{  
      
        private static Lock lock = new ReentrantLock();  
        public void run(){  
            try{  
                //---------a--------------------------  
                //lock.lock();            
                lock.lockInterruptibly(); 
                //lock.tryLock();
                //lock.tryLock(5,TimeUnit.SECONDS); 
                System.out.println(Thread.currentThread().getName() + " running");  
                TimeUnit.SECONDS.sleep(10);             
                System.out.println(Thread.currentThread().getName() + " finished"); 
                lock.unlock();
                
            }catch (InterruptedException e){  
                System.out.println(Thread.currentThread().getName() + " interrupted");  
      
            }  
      
        }  
    } 
    

     

    如果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 
    
  • 相关阅读:
    codeforces 616B Dinner with Emma
    codeforces 616A Comparing Two Long Integers
    codeforces 615C Running Track
    codeforces 612C Replace To Make Regular Bracket Sequence
    codeforces 612B HDD is Outdated Technology
    重写父类中的成员属性
    子类继承父类
    访问修饰符
    方法的参数
    实例化类
  • 原文地址:https://www.cnblogs.com/ynzj123/p/12897620.html
Copyright © 2011-2022 走看看