ReentrantLock

ReentrantLock

  • 在JDK5.0版本之前,重入锁的性能远远好于synchronized关键字,JDK6.0版本之后synchronized 得到了大量的优化,二者性能也不分伯仲,但是重入锁是可以完全替代synchronized关键字的。

  • ReentrantLock在扩展功能上更加强大,比如具有嗅探锁定、多路分支通知等,并且在使用上也比synchronized灵活(另外可以结合Condition来使用)。

  • ReentrantLock支持两种获取锁的方式,一种是公平模型,一种是非公平模型。

ReentrantLock使用例子:

//基本操作
public class ReentrantLockTest implements Runnable{

    private static ReentrantLock lock=new ReentrantLock();
	private static int count=1;
	@Override
	public void run() {
		for(int i=0;i<100;i++){
			lock.lock();
			count++;
			lock.unlock();
		}
	}

	public static void main(String[] args) {
		ReentrantLockTest test1=new ReentrantLockTest();
		ReentrantLockTest test2=new ReentrantLockTest();
	
		Thread thread1=new Thread(test1);
		Thread thread2=new Thread(test2);
		thread1.start();
    	thread2.start();
    	try {
    		//主线程等待thread1和thread2结束后再执行下去
			thread1.join();
			thread2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("count:"+count);
	
	}
}

中断响应

lock 与 lockInterruptibly比较区别在于:

  • lock 优先考虑获取锁,待获取锁成功后,才响应中断。

  • lockInterruptibly 优先考虑响应中断,而不是响应锁的普通获取或重入获取。

对于synchronized块来说,要么获取到锁执行,要么持续等待,interrupt()方法只是单纯地修改由于interrupt值,解决不了死锁问题。而重入锁的中断响应功能就合理地避免了这样的情况。比如,一个正在等待获取锁的线程被“告知”无须继续等待下去,就可以停止工作了。

synchronized例子(不能解决死锁):

//DeadLock
public class KillDeadlockSyn{
    public static void main(String[] args){
        Service service=new Service();
        ThreadA threadA=new ThreadA(service);
        ThreadB threadB=new ThreadB(service);
        threadA.start();
        threadB.start();
        try {
		    Thread.sleep(10000);
		    threadA.interrupt();//是无法中断的,需要在线程中isInterrupted()判断再做处理
	    } catch (InterruptedException e) {
		    // TODO Auto-generated catch block
	    	e.printStackTrace();
	    }
    }
}

class Service {
    Object LockA=new Object();
    Object LockB=new Object();
    public Service() {
    }
    public void methodA(){
        synchronized (LockA){
            System.out.println("methodA----LockA-------begin");
            try {
                Thread.sleep(3000);
                synchronized (LockB){
                    System.out.println("methodA----LockB------begin");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void methodB(){
        synchronized (LockB){
            System.out.println("methodB----LockB------begin");
            try {
                Thread.sleep(3000);
                synchronized (LockA){
                    System.out.println("methodB----LockA------begin");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class ThreadA extends Thread{
    private Service service;
    public ThreadA(Service service) {
        this.service=service;
    }

    @Override
    public void run() {
        service.methodA();
    }
}
class ThreadB extends Thread{
    private Service service;
    public ThreadB(Service service) {
        this.service=service;
    }
    @Override
    public void run() {
        service.methodB();
    }
}

ReentrantLock解决死锁例子:

/**
* 
* @author Administrator
*对于synchronized块来说,要么获取到锁执行,要么持续等待。而重入锁的中断响应功能就合理地避免了这样的情况。
*比如,一个正在等待获取锁的线程被“告知”无须继续等待下去,就可以停止工作了。
 */
public class KillDeadlock implements Runnable{
    public static ReentrantLock lock1 = new ReentrantLock();
    public static ReentrantLock lock2 = new ReentrantLock();
    int lock;

    public KillDeadlock(int lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
       try {
         if (lock == 1) {
                 lock1.lockInterruptibly();  // 以可以响应中断的方式加锁
                 try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {}
                lock2.lockInterruptibly();
                System.out.println("抢lock2成功");
                int count=1;
                while(true){
            	    System.out.println(count++);
                }
            } else {
                lock2.lockInterruptibly();  // 以可以响应中断的方式加锁
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {}
                lock1.lockInterruptibly();
                System.out.println("抢lock1成功");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock1.isHeldByCurrentThread()) lock1.unlock();  // 注意判断方式
            if (lock2.isHeldByCurrentThread()) lock2.unlock();
            System.err.println(Thread.currentThread().getId() + "退出!");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        KillDeadlock deadLock1 = new KillDeadlock(1);
        KillDeadlock deadLock2 = new KillDeadlock(2);
        Thread t1 = new Thread(deadLock1);
        Thread t2 = new Thread(deadLock2);
        t1.start();t2.start();
        Thread.sleep(1000);
        t2.interrupt(); 
    }
}

锁申请等待限时

ReentrantLock可以通过使用tryLock()或者tryLock(long timeout, TimeUtil unit) 来限制等待锁的时间

前者不带参数,这时线程尝试获取锁,如果获取到锁则继续执行,如果锁被其他线程持有,则立即返回 false ,也就是不会使当前线程等待,所以不会产生死锁。
后者带有参数,表示在指定时长内获取到锁则继续执行,如果等待指定时长后还没有获取到锁则返回false。

例子:

public class TryLockTest implements Runnable{
public static ReentrantLock lock = new ReentrantLock();

@Override
public void run() {
	try {
		while(!lock.tryLock(1, TimeUnit.SECONDS)){//一直尝试获取锁
		}
		System.out.println(Thread.currentThread().getName() + "获取锁成功!");
		Thread.sleep(2000);
		lock.unlock();
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
}

public static void main(String[] args) throws InterruptedException {
    TryLockTest test = new TryLockTest();
    Thread t1 = new Thread(test); t1.setName("线程1");
    Thread t2 = new Thread(test); t2.setName("线程2");
    t1.start();
    Thread.sleep(500);
    t2.start();
}
}

结果:
线程1获取锁成功!
线程2获取锁成功!

首先启动线程1,线程1 尝试去获取锁,获取到锁,睡眠2秒,线程2在线程1启动后0.5秒启动,在while语句中一直尝试获取锁,等线程1结束后,线程2获取到锁。

公平锁与非公平锁

ReentrantLock中有两种锁,分别为"公平锁"和"非公平锁"。

公平锁:表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序。

非公平锁:是一种获取锁的抢占机制,随机获取锁,和公平锁不一样的是先来的不一定先拿到锁,这种方式有可能导致某些线程会一直拿不到锁。

源码:

public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}

例子:

public class FairLockTest implements Runnable{
//true则定义为公平锁,false则定义为非公平锁(默认也是非公平锁)
public static ReentrantLock lock = new ReentrantLock(true);
//public static ReentrantLock lock = new ReentrantLock(false);
@Override
public void run() {
    while (true) {
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName() + "获取到了锁!");
        } finally {
            lock.unlock();
        }
    }
}
public static void main(String[] args) throws InterruptedException {
    FairLockTest test = new FairLockTest();
    Thread t1 = new Thread(test, "线程1");
    Thread t2 = new Thread(test, "线程2");
    t1.start();
    t2.start();
}
}

ReentrantLock 配合 Conditond 使用

配合关键字synchronized使用的方法如:await()、notify()、notifyAll(),同样配合ReentrantLock 使用的Conditon提供了以下方法:

public interface Condition {
    void await() throws InterruptedException; // 类似于Object.wait()
    void awaitUninterruptibly(); // 与await()相同,但不会再等待过程中响应中断
    long awaitNanos(long nanosTimeout) throws InterruptedException;
    boolean await(long time, TimeUnit unit) throws InterruptedException;
    boolean awaitUntil(Date deadline) throws InterruptedException;
    void signal(); // 类似于Obejct.notify()
    void signalAll();
}

例子:

public class ReentrantLockWithConditon {

    public static void main(String[] args) throws InterruptedException {
        MyService myService=new MyService();
        ThreadAwait threadAwait=new ThreadAwait(myService);
        new Thread(threadAwait).start();
        Thread.sleep(2000);
        ThreadSingal threadSingal=new ThreadSingal(myService);
        new Thread(threadSingal).start();
    }

}

class MyService{
	public static ReentrantLock lock = new ReentrantLock(true);
    public static Condition condition = lock.newCondition();
    
    public void await(){
    	lock.lock();
    	System.out.println("await:"+new Date());
    	try {
			condition.await();
			System.out.println("after await:"+new Date());
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
    }
    public void signal(){
    	lock.lock();
    	System.out.println("signal:"+new Date());
    	try {
			condition.signal();
			System.out.println("after signal:"+new Date());
		}finally{
			lock.unlock();
		}
    }
}

class ThreadAwait implements Runnable{

	private MyService myService;
	
	public ThreadAwait(MyService myService) {
		this.myService=myService;
	}
	@Override
	public void run() {
		myService.await();
	}
	
}
class ThreadSingal implements Runnable{

	private MyService myService;
	
	public ThreadSingal(MyService myService) {
		this.myService=myService;
	}
	@Override
	public void run() {
		myService.signal();
	}
	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值