您的位置:首页 > 业界新闻

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

2017-06-07 18:18 211 查看
      关键字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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: