互联网技术03——重入锁

重入锁实现细节

在学习重入锁之前,我们先来了解一下可重入锁ReenTrantLock的实现细节。分两种:1.公平锁模型和非公平锁模型

  1. 公平锁:把锁比作只有一个入口的井,获取锁的过程比作打水权。初始化时,state=0, 村民A获得打水权,并将state置为state+1(变为1)。此时村民B来打水,但是只有一个井口,只能生成节点进行等待。这时村民A的家人来打水,可直接获得打水权,并将state+1(变为2),当村民A的家族有一人打完水时,satae-1;这样直到state重新为0,这时村民B获得通知,可以去打水,将打水权交给了B。村民A获得打水权(锁)时,家族人都可以打水,这就是锁重入。
  2. 非公平锁:如果在A打完水,系统通知B这一段时间,村民C来打水,如果是公平锁,C要等待排队,参与锁竞争。如果是非公平锁,C在系统通知B的过程中刚刚好来请求,则可在这个短暂的空闲时间内拿到锁,而不同排队了。
package com.internet.thread;
 
public class SyncDubbo1 {
   
	public synchronized void method1(SyncDubbo1 sd){
		if(Thread.currentThread().getName().equals("t1")){
			Thread t3 = new Thread(new Runnable() {
				
				@Override
				public void run() {
					sd.method2();
				}
			},"t3");
			t3.start();
			System.out.println("线程t1的method1方法执行..");
			method2();
			System.out.println("线程t1的method1调用结束");
		}else if(Thread.currentThread().getName().equals("t2")){
			System.out.println("线程t2的method1方法执行..");
			method2();
			System.out.println("线程t2的method1调用结束");
		}
	}
	public void method2() {
		if(Thread.currentThread().getName().equals("t1")){
			System.out.println("线程t1的method2方法执行..");
			method3();
			System.out.println("线程t1的method2调用结束");
		}else if(Thread.currentThread().getName().equals("t2")){
			System.out.println("线程t2的method2方法执行..");
			method3();
			System.out.println("线程t2的method2调用结束");
		}else if(Thread.currentThread().getName().equals("t3")){
			System.out.println("线程t3的method2方法执行..");
			method3();
			System.out.println("线程t3的method2调用结束");
		}
	}
	public void method3(){
		if(Thread.currentThread().getName().equals("t1")){
			System.out.println("线程t1的method3方法执行完毕");
		}else if(Thread.currentThread().getName().equals("t2")){
			System.out.println("线程t2的method3方法执行完毕");
		}else if(Thread.currentThread().getName().equals("t3")){
			System.out.println("线程t3的method3方法执行完毕");
		}
	}
	
	public static void main(String[] args){
		final SyncDubbo1 sd = new SyncDubbo1();
		Thread t1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				sd.method1(sd);
			}
		},"t1");
		t1.start();
		Thread t2 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				sd.method1(sd);
			}
		},"t2");
		t2.start();
	}
}

执行结果:

线程t1的method1方法执行..
线程t1的method2方法执行..
线程t1的method3方法执行完毕
线程t1的method2调用结束
线程t1的method1调用结束
线程t2的method1方法执行..
线程t3的method2方法执行..
线程t2的method2方法执行..
线程t3的method3方法执行完毕
线程t3的method2调用结束
线程t2的method3方法执行完毕
线程t2的method2调用结束
线程t2的method1调用结束

当method2和method3没有添加synchronized关键字,其运行结果是没有固定顺序的,这就可能造成数据错误,当method2和method3添加synchronized关键字时

package com.internet.thread;
 
public class SyncDubbo1 {
   
	public synchronized void method1(SyncDubbo1 sd){
		if(Thread.currentThread().getName().equals("t1")){
			Thread t3 = new Thread(new Runnable() {
				
				@Override
				public void run() {
					sd.method2();
				}
			},"t3");
			t3.start();
			System.out.println("线程t1的method1方法执行..");
			method2();
			System.out.println("线程t1的method1调用结束");
		}else if(Thread.currentThread().getName().equals("t2")){
			System.out.println("线程t2的method1方法执行..");
			method2();
			System.out.println("线程t2的method1调用结束");
		}
	}
	public synchronized void method2() {
		if(Thread.currentThread().getName().equals("t1")){
			System.out.println("线程t1的method2方法执行..");
			method3();
			System.out.println("线程t1的method2调用结束");
		}else if(Thread.currentThread().getName().equals("t2")){
			System.out.println("线程t2的method2方法执行..");
			method3();
			System.out.println("线程t2的method2调用结束");
		}else if(Thread.currentThread().getName().equals("t3")){
			System.out.println("线程t3的method2方法执行..");
			method3();
			System.out.println("线程t3的method2调用结束");
		}
	}
	public synchronized void method3(){
		if(Thread.currentThread().getName().equals("t1")){
			System.out.println("线程t1的method3方法执行完毕");
		}else if(Thread.currentThread().getName().equals("t2")){
			System.out.println("线程t2的method3方法执行完毕");
		}else if(Thread.currentThread().getName().equals("t3")){
			System.out.println("线程t3的method3方法执行完毕");
		}
	}
	
	public static void main(String[] args){
		final SyncDubbo1 sd = new SyncDubbo1();
		Thread t1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				sd.method1(sd);
			}
		},"t1");
		t1.start();
		Thread t2 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				sd.method1(sd);
			}
		},"t2");
		t2.start();
	}
}

运行结果

线程t1的method1方法执行..
线程t1的method2方法执行..
线程t1的method3方法执行完毕
线程t1的method2调用结束
线程t1的method1调用结束
线程t3的method2方法执行..
线程t3的method3方法执行完毕
线程t3的method2调用结束
线程t2的method1方法执行..
线程t2的method2方法执行..
线程t2的method3方法执行完毕
线程t2的method2调用结束
线程t2的method1调用结束

这是因为当t1有执行method1方法时,获得对象锁,当继续向下执行method2时(因为被synchronized修饰,其锁同method1是同一个锁,切一直被t1线程锁拥有),根据锁重入性质,t1能直接执行method2,以此类推。如果synchronized不支持锁重入,就会造成死锁。我们知道method1方法中需要执行method2,也就是说method1必须执行完method2才能结束并释放这个对象锁,但是执行method2的前提是必须获得这个对象锁,这就造成了死锁。

 

父子类重入锁

 

package com.internet.thread;
 
public class SyncDubbo2 {
    static class Main {
    	public int i = 10;
    	public synchronized void operationSup(){
    		try {
				i--;
				System.out.println("Main print i = "+i);
				Thread.sleep(100);//休息0.1秒
			} catch (Exception e) {
				e.printStackTrace();
			}
    	}
    }
    
    static class Sub extends Main{
    	public synchronized void operationSub(){
    		try {
				while(i > 0){
					i--;
					System.out.println("Sub print i= "+i);
					Thread.sleep(100);
					this.operationSup();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
    	}
    }
    
    public static void main(String[] args){
    	Thread t1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				Sub sub = new Sub();
				sub.operationSub();
			}
		});
    	t1.start();
    }
}

 

执行结果

Sub print i= 9
Main print i = 8
Sub print i= 7
Main print i = 6
Sub print i= 5
Main print i = 4
Sub print i= 3
Main print i = 2
Sub print i= 1
Main print i = 0

每次执行sub的operationSub方法时,都需要执行main的operationSub方法,看运行结果可知,是按顺序执行,所以父子间也支持锁重入

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值