synchronized和ReentrantLock

synchronized

synchronized 是一个 JVM 提供实现的内部锁机制。一个 synchronized 块包括一个锁对象引用和代码块。
synchronized 作用在方法上时,其锁对象是方法所在对象本身。

使用 synchronized 时至多只有一个线程可以获得锁。当线程进入 synchronized 代码块时自动获取锁,离开代码块时自动释放锁。

synchronized 同时也是一个支持可重入的互斥锁,同一个线程可以多次进入同步块。

public class WaitNotify {
    static boolean flag = true;
    static Object lock = new Object();

    public static void main(String args[]) throws InterruptedException {
        Thread waitThread = new Thread(new Wait(), "WaitThread");
        waitThread.start();
        TimeUnit.SECONDS.sleep(1);
        Thread notifyThread = new Thread(new Notify(), "NotifyThread");
        notifyThread.start();
    }

    static class Wait implements Runnable {
        @Override
        public void run() {
            synchronized (lock) { //获取锁
                while (flag) {
                    try {
                        System.out.println(Thread.currentThread() + " flag is true. wait @"
                                + new SimpleDateFormat("HH:mm:ss").format(new Date()));

                        //等待, 并释放锁
                        lock.wait();
                        //重新获得锁之后从 wait() 返回
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread() + " flag is false. running @ " +
                        new SimpleDateFormat("HH:mm:ss").format(new Date()));
            }
        }
    }

    static class Notify implements Runnable {
        @Override
        public void run() {
            synchronized (lock) {
                System.out.println(Thread.currentThread() + " hold lock. notify @ "
                    + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                //通知等待的线程
                lock.notifyAll();
                flag= false;
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //直到同步块结束才释放锁给 wait() 线程
            }
            synchronized (lock) {
                System.out.println(Thread.currentThread() + " hold lock again. notify @ "
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            }
        }
    }
}

ReentrantLock

ReentrantLock 也是一个可重入的互斥锁。 它是一个J.U.C包中实现了 Lock 接口的类。Lock 接口定义了下面一些方法:

void        lock(); //获取锁
void        lockInterruptibly(); //可被中断获取锁
Condition   newCondition(); //返回一个绑定在此锁上的 condition 实例
boolean     tryLock(); //尝试获取锁,立即返回结果
boolean     tryLock(long time, TimeUnit unit); // 定时获取锁,不可被中断
void        unlock(); //释放锁

ReentrantLock 对比内部锁首先最明显的一个区别就是 ReentrantLock 锁的获取和释放都需要显示地手动调用方法。
获取锁时调用 lock()tryLock() ,释放锁时调用 unlock() .
ReentrantLock 锁的实现是通过和继承自 AQS 的同步器组合使用实现的,而非JVM实现。
ReentrantLock 对锁的控制程度比 synchronized 要高,更灵活,在获取锁时可以中断线程,或者设置最大等待时间等等。

public class LockTest {
    private Lock lock = new ReentrantLock();

    public void do1() throws InterruptedException {
        try {
            lock.lock();
            //do something...
        } finally {
            lock.unlock();
        }
    }

    public void do2() {
        try{        
            lock.lock();
            //do something...
        } finally {
            lock.unlock();
        }
    }
}

小结

通过一个表格来对比一下两者区别

项目synchronizedReentrantLock
锁实现层次java关键字,JVM实现J.U.C下面的一个类,结合 AQS 实现的锁机制
锁获取进入代码块自动获取手动调用方法lock()tryLock()获取
锁释放离开代码块自动释放手动调用方法 unlock() 释放
锁类型可重入,不可中断、非公平可重入、可中断、公平或非公平可控
等待队列只等有一个等待队列通过组合 Condition 实现多个等待队列

参考:

https://blog.csdn.net/u012403290/article/details/64910926?locationNum=11&fps=1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值