java多线程基础---synchronized与ReentrantReadWriteLock的介绍与比较

(1) 创建一个ReentrantReadWriteLock对象

[java]  view plain  copy
  1. private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();  

(2)抽取读锁和写锁:

[java]  view plain  copy
  1. private Lock readLock = rwl.readLock();//得到一个可被多个读操作共用的读锁,但它会排斥所有写操作  
  2. private Lock writeLock = rwl.writeLock();//得到一个写锁,它会排斥所有其他的读操作和写操作  

(3) 对所有访问者加读锁

[java]  view plain  copy
  1. public double getTotalBalance(){  
  2.     readLock.lock();  
  3.     try{...};  
  4.     finally{readLock.unlock();}  
  5. }  

对所有修改者加写锁

[java]  view plain  copy
  1. public void transfer(){  
  2.     writeLock.lock();  
  3.     try{...};  
  4.     finally{writeLock.unlock();}  
  5. }  
1、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是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}

3、在资源竞争不是很激烈的情况下Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;


可重入的锁ReentrantLock:使用ReentrantLock锁最简单的一个例子:
复制内容到剪贴板
代码:
    Lock lock = new ReentrantLock();  
    try {  
        lock.lcok();  
        // do something  
    } finally {  
        lock.unlock();  
    }  
上面这段代码,首先创建了一个lock,然后调用它的lock()方法,开启锁定,在最后调用它的unlock()解除锁定。值得注意的时,一般在使用锁时,都应该按上面的风格书写代码,即lock.unlock()最好放在finally块,这样可以防止,执行do something时发生异常后,导致锁永远无法被释放。注意:lock与unlock一定要 配对。
到此,还没发现Lock与synchronized有什么不同,Lock与synchronized不同之处主要体现在Lock比synchronized更灵活得多,而这些灵活又主要体现在如下的几个方法

//lock()
tryLock()
tryLock(long timeout, TimeUnit timeUnit)
lockInterruptibly()

//unlock()

A、 trylock()方法 :如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;
B、 tryLock(long timeout, TimeUnit timeUnit)方法 :如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;
是不是比synchronized灵活就体现出来了,打个不是很恰当的比分:你现在正在忙于工作,突然感觉内急,于是你跑向洗手间,到门口发现一个“清洁中,暂停使用”的牌牌。没办法,工作又忙,所以你只好先放弃去洗手间回去忙工作,可能如此反复,终于你发现可以进了,于是......
像这样的场景用synchronized你怎么实现?没办法,如果synchronized,当你发现洗手间无法暂时无法进入时,就只能乖乖在门口干等了。而使用trylock()呢,首先你试着去洗手间,发现暂时无法进入(trylock返回false),于是你继续忙你的工作,如此反复,直到可以进入洗手间为止(trylock返回true)。甚至,你非常急,你可以尝试性的在门口等20秒,不行再去忙工作(trylock(20, TimeUnit.SECONDS);)。
C、 lockInterruptibly()方法
lockInterruptibly()方法的执行如下:

如果该锁定没有被另一个线程保持,则获取该锁定并立即返回,将锁定的保持计数设置为 1。
如果当前线程已经保持此锁定,则将保持计数加 1,并且该方法立即返回。
如果锁定被另一个线程保持,则出于线程调度目的,禁用当前线程,并且在发生以下两种情况之一以前,该线程将一直处于休眠状态:
    a、锁定由当前线程获得;
    b、或者其他某个线程中断当前线程。 
如果当前线程获得该锁定,则将锁定保持计数设置为1。
如果当前线程:
    a、在进入此方法时已经设置了该线程的中断状态;
    b、或者在等待获取锁定的同时被中断。 
则抛出 InterruptedException,并且清除当前线程的已中断状态。
即lockInterruptibly()方法允许在等待时由其它线程调用它的Thread.interrupt方法来中断等待而直接返回,这时不再获取锁,而会抛出一个InterruptedException。

ReentrantReadWriteLock可以作为公平锁和非公平锁

公平锁:所有等待锁的线程都保存着一个队列中,当获得锁的线程执行完毕释放锁之后,队列中线程按照先进先出的顺序获取锁
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);


非公平锁:,所有等待锁的线程都保存着一个队列中,当获得锁的线程执行完毕释放锁之后,JVM会在等待队列中随机挑选一个等待线程获取锁
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(false);




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值