本文共 4275 字,大约阅读时间需要 14 分钟。
之前说了线程同步机制Synchronize锁,其实除此之外还有一种JUC的Lock锁也能实现线程同步。而且Lock实现类ReentrantLock相比Synchronize有更大的灵活性,更加丰富,更是适合大多场景的使用。
先来简单的对比下ReentrantLock和Synchronize吧。
- Synchronsize锁是独占锁,加锁和释放锁都是自动的,只要加上关键字synchronize或者代码块就行。使用起来很简单,但是呢灵活性较差。ReentrantLock也是独占锁,但是它需要手动的加锁(lock等)和释放锁(unlock),使用的起来相对复杂了点,但是灵活性好,且ReentrantLock提供了丰富的方法。
- Synchronsize和ReentrantLock都是可重入锁(可以多次使用锁:举个例子,方法A使用了锁,其实调用B,但是B也使用了锁,这是调用B的时候不用重新获取锁)。但是都是需要释放锁才能让其它线程拿到锁。
- Synchronize一旦拿不到锁,产生了死锁等待状态时,相应不能中断,而ReentrantLock提供了相应中单的锁。
- 最主要的就是ReentrantLock还可以实现公平锁机制。什么叫公平锁呢?也就是在锁上等待时间最长的线程将获得锁的使用权。通俗的理解就是谁排队时间最长谁先执行获取锁。
与Synchronize不同的是,ReentrantLock提供了多个锁,可以根据不同需求处理线程同步问题。下面我们重点介绍下ReentrantLock锁,Synchronize的介绍请查看之前的博客。
ReentrantLock是JUC包下的类(java.util.concurrent.locks.ReentrantLock),实现了Lock接口。
ReentrantLock的释放锁都是一样unlock方法,下面主要看下ReentrantLock不同的锁。 不实现线程同步的时候,不加锁效果:public class ReenTrantLockThread { public static void main(String[] args) { ThreadTest threadTest = new ThreadTest(); new Thread(threadTest,"小明").start(); new Thread(threadTest,"小王").start(); }}class ThreadTest implements Runnable{ final Lock lock = new ReentrantLock(); @Override public void run() { study(); } public void study(){ for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+":我正在学习"); } }}
结果:
小明和小王疯由cpu调度学习。加了锁之后,让一个人学习完再下一个线程拿锁学习(注意哦,下一个线程不一定是另一个人哦,由cpu调度)(1)Lock() 这个锁就是普通也是常用的锁,和Synchronize锁差不多,一旦拿到锁之后必须等待释放锁,才能继续拿锁,否则会出现线程死锁,所以使用结束之后一定要释放锁。
注意:为了防止不释放锁,一般将加锁内容放到try里面,然后在finally里面释放锁,这样保证一定会释放锁。public void study(){ lock.lock(); try { / for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName()+":我正在学习"); } }catch (Exception e){ }finally { lock.unlock() } }
结果: 让一个人学习完再下一个线程拿锁学习!!!
(2) tryLock()锁,我叫它尝试锁,它是用来尝试获取锁,如果能获取到那么可以占有锁使用,如果拿不到我们也可以处理其他事物。它是有返回值的,类型boolean,如果拿到了锁就返回true,拿不到就返回false,所以不管怎么的它都会立马返回一个值。
public void study(){ boolean flag = lock.tryLock(); if(flag){ try { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName()+":我正在学习"); } }catch (Exception e){ }finally { lock.unlock(); } }else { System.out.println(Thread.currentThread().getName()+":我没拿到锁,那我去看电视了"); } }
结果:
(3)tryLock(long timeout, TimeUnit unit),用法跟tryLock是一样的,不同的是可以指定等待时间,就是锁我拿锁,如果指定时间后还没拿到锁我就返回false,时间没到那我就继续等待锁释放。public void study() throws InterruptedException { boolean flag = lock.tryLock(5000,TimeUnit.MILLISECONDS); // 等待5秒钟拿不到锁就返回false if(flag){ try { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName()+":我正在学习"); } }catch (Exception e){ }finally { lock.unlock(); } }else { System.out.println(Thread.currentThread().getName()+":我没拿到锁,那我去看电视了"); } }
结果:5秒内成功拿到锁。
我们给线程加上一个sleep,让线程休息总时间超过5秒, (4)lockInterruptibly()中断锁,使用这个锁可有主动主断线程使用Thread.interrupt()。前提是这个线程用到锁了,在没有用锁的情况下是用不了的。这个不好演示,用法如下: 然后说说ReentrantLock特殊的锁机制,公平锁和非公平锁。 就跟字面上意思差不多, 公平锁意思就是哪个线程排队时间长就让谁优点调度。 非公平锁意思就是不管线程啥时候开始排的队,我就让cpu看心情调度。 使用方法非常简单,只需要在初始化锁的时候加上,true(公平)或者false(不公平)参数。默认就是false 公平锁:final Lock lock = new ReentrantLock(true);public void study() throws InterruptedException { for (int i = 0; i <2 ; i++) { try { lock.lock(); // 等待5秒钟拿不到锁就返回false System.out.println(Thread.currentThread().getName()+":我正在学习"); //Thread.sleep(2000); }catch (Exception e){ }finally { lock.unlock(); } } }
结果:大家不要挤,人人有份。
非公平锁:final Lock lock = new ReentrantLock(false); public void study() throws InterruptedException { for (int i = 0; i <2 ; i++) { try { lock.lock(); // 等待5秒钟拿不到锁就返回false System.out.println(Thread.currentThread().getName()+":我正在学习"); //Thread.sleep(2000); }catch (Exception e){ }finally { lock.unlock(); } } }
结果:
下片介绍:读写锁。转载地址:http://njhof.baihongyu.com/