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 
原文地址:https://www.cnblogs.com/ynzj123/p/12897620.html