说到ReentrantLock,肯定要提一下synchronized,两者都是解决并发的重要工具。在jdk5的版本,重入锁的性能是好于synchronized,但是从6开始,jdk对synchronized做了很多的优化,目前两者性能相差不大,官方建议synchronized的方式。
说一下两者的相同点和不同点:
相同点:
(1)都是可重入锁,同一个线程每进入一次,锁的计数器都自增1,等到锁的计数器值降为0时才会释放锁。
不同点:
(1)使用方式不同,synchronized依赖于JVM实现的,而ReentrantLock是JDK实现的。synchronized由编译器去保证锁的加锁和释放,而ReentrantLock使用起来相当灵活,需要手动添加lock和unlock方法。
(2) ReenTrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。
(3)ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。
(4) ReenTrantLock是可中断锁,通过lock.lockInterruptibly()来实现。
1.ReentrantLock基本用法
class ReenterLock implements Runnable{
public static ReentrantLock reentrantLock=new ReentrantLock();
public static int i=0;
@Override
public void run(){
for(int j=0;j<1000;j++){
reentrantLock.lock();
//reentrantLock.lock();
try{
i++;
}finally {
reentrantLock.unlock();
//reentrantLock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
ReenterLock reenterLock=new ReenterLock();
Thread t1=new Thread(reenterLock);
Thread t2=new Thread(reenterLock);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("i:"+i);
}
}
生成两个线程,让主线程等待两个线程执行完毕,t1和t2相当于并行。手动加锁和释放锁,lock和unlock次数要保持一致,因为ReentrantLock持有一个所计数器,当已持有锁的线程再次获得该锁时计数器值加1,每调用一次lock.unlock()时所计数器值减一,直到所计数器值为0,此时线程释放锁。
2.中断响应
ReenTrantLock是可中断锁,通过lock.lockInterruptibly()来实现。此方法也是加锁的动作,只是可以对中断产生响应 :
class ReenterLock implements Runnable{
public static ReentrantLock reentrantLock=new ReentrantLock();
public static ReentrantLock reentrantLock2=new ReentrantLock();
int flag;
public static int i=0;
ReenterLock(int flag){
this.flag=flag;
}
@Override
public void run(){
try{
if(flag==1){
reentrantLock.lockInterruptibly();
try{
Thread.sleep(500);
System.out.println("11");
}catch (Exception e){
e.printStackTrace();
}
reentrantLock2.lockInterruptibly();
}else{
reentrantLock2.lockInterruptibly();
try{
Thread.sleep(500);
System.out.println("22");
}catch (Exception e){
e.printStackTrace();
}
reentrantLock.lockInterruptibly();
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(reentrantLock.isHeldByCurrentThread()){
reentrantLock.unlock();
}
if(reentrantLock2.isHeldByCurrentThread()){
reentrantLock2.unlock();
}
System.out.println(Thread.currentThread().getId()+":线程退出");
}
}
public static void main(String[] args) throws InterruptedException {
ReenterLock reenterLock=new ReenterLock(1);
ReenterLock reenterLock2=new ReenterLock(2);
Thread t1=new Thread(reenterLock);
Thread t2=new Thread(reenterLock2);
t1.start();
t2.start();
//t1.join();
//t2.join();
Thread.sleep(1000);
t1.interrupt();
System.out.println("i:"+i);
}
启动t1和t2之后,两个线程会互相等待,形成死锁。这时候主动中断t1线程,t1放弃任务退出,t2获取锁完成任务退出。
3.锁申请等待限时
用tryLock实现限时等待,超出时间还没有得到锁的时候,放弃等待:
class TimerLock implements Runnable{
public static ReentrantLock reentrantLock=new ReentrantLock();
int flag;
public static int i=0;
@Override
public void run(){
try{
if (reentrantLock.tryLock(5, TimeUnit.SECONDS)) {
System.out.println(Thread.currentThread().getId());
Thread.sleep(6000);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(reentrantLock.isHeldByCurrentThread()){
reentrantLock.unlock();
}
System.out.println(Thread.currentThread().getId()+":线程退出");
}
}
public static void main(String[] args) throws InterruptedException {
TimerLock reenterLock=new TimerLock();
Thread t1=new Thread(reenterLock);
Thread t2=new Thread(reenterLock);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("i:"+i);
}
}
tryLock()会返回值,true代表成功获取到锁,false代表获取锁失败。不带时间参数的时候,会直接返回true或false。这样返回参数之后就可以通过返回值来控制等待与否,从而有效的避免死锁:
class ReenterLock implements Runnable{
public static ReentrantLock reentrantLock=new ReentrantLock();
public static ReentrantLock reentrantLock2=new ReentrantLock();
int flag;
public static int i=0;
ReenterLock(int flag){
this.flag=flag;
}
@Override
public void run(){
try{
if(flag==1){
//用while来不停的获取锁的状态,尝试加锁
while (true) {
if (reentrantLock.tryLock()) {
try {
Thread.sleep(500);
System.out.println("11");
// 尝试获取第二个锁
if (reentrantLock2.tryLock()) {
try {
Thread.sleep(500);
System.out.println("2222");
return;
}finally {
reentrantLock2.unlock();
}
}
}finally {
System.out.println("-----");
reentrantLock.unlock();
}
}
}
}else{
//用while来不停的获取锁的状态,尝试加锁
while (true) {
if (reentrantLock2.tryLock()) {
try {
Thread.sleep(500);
System.out.println("33");
// 尝试获取第二个锁
if (reentrantLock.tryLock()) {
try {
Thread.sleep(500);
System.out.println("44");
return;
}finally {
reentrantLock.unlock();
}
}
}finally {
System.out.println("-----");
reentrantLock2.unlock();
}
}
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println(Thread.currentThread().getId()+":线程退出");
}
}
public static void main(String[] args) throws InterruptedException {
ReenterLock reenterLock=new ReenterLock(1);
ReenterLock reenterLock2=new ReenterLock(2);
Thread t1=new Thread(reenterLock);
Thread t2=new Thread(reenterLock2);
t1.start();
t2.start();
//t1.join();
//t2.join();
//Thread.sleep(1000);
//t1.interrupt();
System.out.println("i:"+i);
}
}