学习互联网架构第三课(synchronized重入锁)

      关键字synchronized拥有锁重入的功能,也就是在使用synchronized时,当一个线程得到了一个对象的锁后,再次请求此对象时是可以再次得到该对象的锁。关于重入锁的理解,大家可以参考http://blog.csdn.net/u012453843/article/details/72884920这篇博客进行学习。

      下面我们来看一个示例,如下所示:

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();
	}
}
        可以看到method2和method3没有添加synchronized关键字,运行结果如下(列出的只是一种运行结果,还有其他结果):

线程t1的method1方法执行..
线程t3的method2方法执行..
线程t1的method2方法执行..
线程t3的method3方法执行完毕
线程t1的method3方法执行完毕
线程t3的method2调用结束
线程t1的method2调用结束
线程t1的method1调用结束
线程t2的method1方法执行..
线程t2的method2方法执行..
线程t2的method3方法执行完毕
线程t2的method2调用结束
线程t2的method1调用结束
         可以看到线程t1和t3执行method2和method3的顺序是不固定的,这样就可能有问题,在处理可能出现线程问题的情况时,我们更希望线程执行的时候不要交叉执行,那么我们可以在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();
	}
}
         我们再执行main方法,运行结果如下

线程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执行完之后才执行的线程t3,最后执行的是线程t2,线程t1由方法method1要去执行由synchronized修饰的method2,直接便可以获取到锁,这种情况便是锁重入。如果synchronized不支持锁重入的话,会造成死锁的情况(method1还没执行完,要执行method2,method2不让获取锁的话,method1就执行不完了)。
         上面说的是一种锁重入的场景,锁重入还有一种常见的情形,那就是父子类的情况,再看一个例子

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和Main类的方法交替执行,而这两个方法都有synchronized修饰,说明父子类的情况锁重入也是可以的。

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值