前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >你可能不了解的Synchonized和ReentrantLock

你可能不了解的Synchonized和ReentrantLock

作者头像
PhoenixZheng
发布2018-08-07 16:48:25
3690
发布2018-08-07 16:48:25
举报
文章被收录于专栏:Phoenix的Android之旅

面试中经常会问到的一类问题是多线程相关的, 比如如何处理Android中的多线程通信,如何处理并发问题。归根结底,处理Java的并发,都离不开锁。 我们将花三到四分钟了解两种锁的用法和不同, 还有什么是公平锁。

ReentrantLock 和 Synchronized 的比较

相同:ReentrantLock提供了synchronized类似的功能和内存语义。 不同: (1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现; (2)ReentrantLock功能性方面更全面,比如时间锁等候,可中断锁等候,锁投票等,因此更有扩展性。在多个条件变量和高度竞争锁的地方,用ReentrantLock更合适,ReentrantLock还提供了Condition,对线程的等待和唤醒等操作更加灵活,一个ReentrantLock可以有多个Condition实例,所以更有扩展性。 (3)ReentrantLock 的性能比synchronized会好点。 (4)ReentrantLock提供了可轮询的锁请求,他可以尝试的去取得锁,如果取得成功则继续处理,取得不成功,可以等下次运行的时候处理,所以不容易产生死锁,而synchronized则一旦进入锁请求要么成功,要么一直阻塞,所以更容易产生死锁。

如何加锁
Synchronized

加锁有两种,方法同步(给方法增加synchronized声明)和代码块同步(给代码块增加synchronized声明)

ReentrantLock

获取锁的方式是通过 ReentrantLock 的对象 lock()来获取锁的, 必须记住一定要在finally方法中调用 unlock() 释放锁

关于锁的重入

锁是可以重复获取的,Synchronized和 ReentrantLock都是

代码语言:javascript
复制
public class SynchronizedTest {
    public void method1() {
        synchronized (SynchronizedTest.class) {
            System.out.println("方法1获得ReentrantTest的锁运行了");
            method2();
        }
    }
    public void method2() {
        synchronized (SynchronizedTest.class) {
            System.out.println("方法1里面调用的方法2重入锁,也正常运行了");
        }
    }
    public static void main(String[] args) {        
        new SynchronizedTest().method1();
    }
}
代码语言:javascript
复制
public class ReentrantLockTest {
    private Lock lock = new ReentrantLock();
    public void method1() {
        lock.lock();        
        try {
            System.out.println("方法1获得ReentrantLock锁运行了");
            method2();
        } finally {
            lock.unlock();
        }
    }
    public void method2() {
        lock.lock();        
        try {
            System.out.println("方法1里面调用的方法2重入ReentrantLock锁,也正常运行了");
        } finally {
            lock.unlock();
        }
    }
    public static void main(String[] args) {        
        new ReentrantLockTest().method1();
    }
}
听说过公平锁吗?

Synchronized持有的锁是非公平的,因为CPU的调度算法是随机从等待队列里挑选一个线程, 可能会导致优先级低的线程永远得不到锁。 而ReentrantLock可以通过在构造方法中传入true来构造公平锁,保证线程按照时间的先后顺序执行。

代码语言:javascript
复制
public class LockFairTest implements Runnable{    //创建公平锁
    private static ReentrantLock lock=new ReentrantLock(true);
    public void run() {
        while(true){
            lock.lock();
            try{
                System.out.println(Thread.currentThread().getName()+"获得锁");
            }finally{
                lock.unlock();
            }
        }
    }
    public static void main(String[] args) {
        LockFairTest lft=new LockFairTest();
        Thread th1=new Thread(lft);
        Thread th2=new Thread(lft);
        th1.start();
        th2.start();
    }
}

结果如下

代码语言:javascript
复制
Thread-1获得锁
Thread-0获得锁
Thread-1获得锁
Thread-0获得锁
Thread-1获得锁
Thread-0获得锁
Thread-1获得锁
Thread-0获得锁
Thread-1获得锁
Thread-0获得锁
Thread-1获得锁
总结

区别: 1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;

2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;

3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;

4)通过Lock可以知道有没有成功获取锁(tryLock()),而synchronized却无法办到。

5)Lock可以提高多个线程进行读操作的效率。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-02-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Android每日一讲 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ReentrantLock 和 Synchronized 的比较
  • 如何加锁
    • Synchronized
      • ReentrantLock
      • 关于锁的重入
      • 听说过公平锁吗?
      • 总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档