基础篇:同步机制之synchronized与ReentrantLock(五)

我们继续来探讨同步机制的话题;

上一篇文章说到了使用ReentrantLock的lock()来获取锁,但有时候我们可能有这样的需求,我们先尝试着去获取锁,但等了几秒实在拿不到锁就放弃获取锁而转做其它的事情,这个需求是很常见的, 所幸的是,ReentrantLock提供了tryLock方法来帮助我们达到这样的目的;

//演示锁的tryLock方法
	public static void testTrylock() throws InterruptedException{
		final ReentrantLock lock = new ReentrantLock();
		//开启一个线程A,让它先拿到锁,再休眠几秒
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					lock.lock();
					System.out.println("线程A已拿到锁,并且休眠8秒");
					TimeUnit.MILLISECONDS.sleep(8000);
					System.out.println("线程A执行完毕!");
				} catch (Exception e) {
					e.printStackTrace();
				}finally{
					lock.unlock();
				}
			}
		}).start();
		
		//开启一个线程B
		new Thread(new Runnable() {
			@Override
			public void run() {
				boolean holdLock = false;
				try {
					TimeUnit.MILLISECONDS.sleep(10);
					System.out.println("线程B尝试获取锁");
					
//					lock.lock();
//					System.out.println("线程B拿到锁,准备载入资源...");
//					如果我们写上面的代码,很明显,lock.lock()这里必须等待8秒等到线程A执行完毕才能拿到锁,后面所有的执行都会被阻塞
//					,但有时候我们想先等几秒看看,实在拿不到锁就做其它事,这时我们可以这么写,如下所示:
					
					//尝试获取锁,3秒后拿不到锁就做其它事
					holdLock = lock.tryLock(3000, TimeUnit.MILLISECONDS);
					if(holdLock){
						System.out.println("拿到锁,准备载入资源...");
					}else{
						System.out.println("拿不到锁...放弃载入资源...");
					}
				} catch(Exception e){
					e.printStackTrace();
				} finally {
					if(holdLock){
						lock.unlock();
					}
				}
			}
		}).start();
	}

输出**********************************************************************

线程A已拿到锁,并且休眠8秒
线程B尝试获取锁
拿不到锁...放弃载入资源...
线程A执行完毕!

***************************************************************************

tryLock这个比较简单,不再多说,最后,我们来证明一下锁机制锁住的是当前对象;

//演示锁机制是作用与对象之上的!
	public static void testObjSyn(){
		//证论:如果对象A有方法b,c,d     b,c方法均加锁,d为普通方法
		//如果线程T持有A对象的锁且进入方法b,则其余线程无法进入方法c但可以进入普通方法d
		//节省代码,直接写内部类了!
		class A{
			
			//声明一个对象,专门用作锁,在实际运用中,你不要直接写个Object,而是要持有一个有意义的对象
			//Object synObj = new Object();  //*****代码1处******
			public synchronized void b(){
				try {
					TimeUnit.MILLISECONDS.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("A.b()");
			}
			public void c(){
//				synchronized (synObj) { //*****代码2处******
				synchronized (this) {
					System.out.println("A.c()");
				}
			}
			public void d(){
				System.out.println("A.d()");
			}
		}
		
		final A aObj = new A();
		new Thread(new Runnable() {
			public void run() {aObj.b();}
		}).start();
		
		new Thread(new Runnable() {
			public void run() {aObj.c();}
		}).start();
		
		new Thread(new Runnable() {
			public void run() {aObj.d();}
		}).start();
		
		
	}

运行后,我们看到输出结果是,先输出A.d() ; 等两秒后再一并输出A.b() A.c();


结论:第一个线程调用b()时,锁定的是当前的对象也就是aObj,第二线程调用c()时,该对象锁继续被第一个线程持有,所以无法获取到锁,但d()是普通方法,无需获取锁所以能调用;

解决办法:如果b()和c()两个方法无任何业务关联性,根本不需要在同一把锁中执行,则可以声明一把新锁;(业务关联性是指:假设b()方法是下单,c()是减库存,则两个方法必须一起执行,c()的执行依赖于b()的执行结果)

将代码1处于代码2处的注释去掉,在A类中声明一把新锁synObj,再运行试试看;




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值