互联网架构第三课

来源:互联网 发布:淘宝女装店铺改卖男装 编辑:程序博客网 时间:2024/06/05 13:25

欢迎

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

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

[html] view plain copy
print?
  1. package com.internet.thread;  
  2.   
  3. public class SyncDubbo1 {  
  4.      
  5.     public synchronized void method1(SyncDubbo1 sd){  
  6.         if(Thread.currentThread().getName().equals(“t1”)){  
  7.             Thread t3 = new Thread(new Runnable() {  
  8.                   
  9.                 @Override  
  10.                 public void run() {  
  11.                     sd.method2();  
  12.                 }  
  13.             },”t3”);  
  14.             t3.start();  
  15.             System.out.println(“线程t1的method1方法执行..”);  
  16.             method2();  
  17.             System.out.println(“线程t1的method1调用结束”);  
  18.         }else if(Thread.currentThread().getName().equals(“t2”)){  
  19.             System.out.println(“线程t2的method1方法执行..”);  
  20.             method2();  
  21.             System.out.println(“线程t2的method1调用结束”);  
  22.         }  
  23.     }  
  24.     public void method2() {  
  25.         if(Thread.currentThread().getName().equals(“t1”)){  
  26.             System.out.println(“线程t1的method2方法执行..”);  
  27.             method3();  
  28.             System.out.println(“线程t1的method2调用结束”);  
  29.         }else if(Thread.currentThread().getName().equals(“t2”)){  
  30.             System.out.println(“线程t2的method2方法执行..”);  
  31.             method3();  
  32.             System.out.println(“线程t2的method2调用结束”);  
  33.         }else if(Thread.currentThread().getName().equals(“t3”)){  
  34.             System.out.println(“线程t3的method2方法执行..”);  
  35.             method3();  
  36.             System.out.println(“线程t3的method2调用结束”);  
  37.         }  
  38.     }  
  39.     public void method3(){  
  40.         if(Thread.currentThread().getName().equals(“t1”)){  
  41.             System.out.println(“线程t1的method3方法执行完毕”);  
  42.         }else if(Thread.currentThread().getName().equals(“t2”)){  
  43.             System.out.println(“线程t2的method3方法执行完毕”);  
  44.         }else if(Thread.currentThread().getName().equals(“t3”)){  
  45.             System.out.println(“线程t3的method3方法执行完毕”);  
  46.         }  
  47.     }  
  48.       
  49.     public static void main(String[] args){  
  50.         final SyncDubbo1 sd = new SyncDubbo1();  
  51.         Thread t1 = new Thread(new Runnable() {  
  52.               
  53.             @Override  
  54.             public void run() {  
  55.                 sd.method1(sd);  
  56.             }  
  57.         },”t1”);  
  58.         t1.start();  
  59.         Thread t2 = new Thread(new Runnable() {  
  60.               
  61.             @Override  
  62.             public void run() {  
  63.                 sd.method1(sd);  
  64.             }  
  65.         },”t2”);  
  66.         t2.start();  
  67.     }  
  68. }  
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关键字,运行结果如下(列出的只是一种运行结果,还有其他结果):

[html] view plain copy
print?
  1. 线程t1的method1方法执行..  
  2. 线程t3的method2方法执行..  
  3. 线程t1的method2方法执行..  
  4. 线程t3的method3方法执行完毕  
  5. 线程t1的method3方法执行完毕  
  6. 线程t3的method2调用结束  
  7. 线程t1的method2调用结束  
  8. 线程t1的method1调用结束  
  9. 线程t2的method1方法执行..  
  10. 线程t2的method2方法执行..  
  11. 线程t2的method3方法执行完毕  
  12. 线程t2的method2调用结束  
  13. 线程t2的method1调用结束  
线程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关键字,代码如下

[html] view plain copy
print?
  1. package com.internet.thread;  
  2.   
  3. public class SyncDubbo1 {  
  4.      
  5.     public synchronized void method1(SyncDubbo1 sd){  
  6.         if(Thread.currentThread().getName().equals(“t1”)){  
  7.             Thread t3 = new Thread(new Runnable() {  
  8.                   
  9.                 @Override  
  10.                 public void run() {  
  11.                     sd.method2();  
  12.                 }  
  13.             },”t3”);  
  14.             t3.start();  
  15.             System.out.println(“线程t1的method1方法执行..”);  
  16.             method2();  
  17.             System.out.println(“线程t1的method1调用结束”);  
  18.         }else if(Thread.currentThread().getName().equals(“t2”)){  
  19.             System.out.println(“线程t2的method1方法执行..”);  
  20.             method2();  
  21.             System.out.println(“线程t2的method1调用结束”);  
  22.         }  
  23.     }  
  24.     public synchronized void method2() {  
  25.         if(Thread.currentThread().getName().equals(“t1”)){  
  26.             System.out.println(“线程t1的method2方法执行..”);  
  27.             method3();  
  28.             System.out.println(“线程t1的method2调用结束”);  
  29.         }else if(Thread.currentThread().getName().equals(“t2”)){  
  30.             System.out.println(“线程t2的method2方法执行..”);  
  31.             method3();  
  32.             System.out.println(“线程t2的method2调用结束”);  
  33.         }else if(Thread.currentThread().getName().equals(“t3”)){  
  34.             System.out.println(“线程t3的method2方法执行..”);  
  35.             method3();  
  36.             System.out.println(“线程t3的method2调用结束”);  
  37.         }  
  38.     }  
  39.     public synchronized void method3(){  
  40.         if(Thread.currentThread().getName().equals(“t1”)){  
  41.             System.out.println(“线程t1的method3方法执行完毕”);  
  42.         }else if(Thread.currentThread().getName().equals(“t2”)){  
  43.             System.out.println(“线程t2的method3方法执行完毕”);  
  44.         }else if(Thread.currentThread().getName().equals(“t3”)){  
  45.             System.out.println(“线程t3的method3方法执行完毕”);  
  46.         }  
  47.     }  
  48.       
  49.     public static void main(String[] args){  
  50.         final SyncDubbo1 sd = new SyncDubbo1();  
  51.         Thread t1 = new Thread(new Runnable() {  
  52.               
  53.             @Override  
  54.             public void run() {  
  55.                 sd.method1(sd);  
  56.             }  
  57.         },”t1”);  
  58.         t1.start();  
  59.         Thread t2 = new Thread(new Runnable() {  
  60.               
  61.             @Override  
  62.             public void run() {  
  63.                 sd.method1(sd);  
  64.             }  
  65.         },”t2”);  
  66.         t2.start();  
  67.     }  
  68. }  
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方法,运行结果如下

[html] view plain copy
print?
  1. 线程t1的method1方法执行..  
  2. 线程t1的method2方法执行..  
  3. 线程t1的method3方法执行完毕  
  4. 线程t1的method2调用结束  
  5. 线程t1的method1调用结束  
  6. 线程t3的method2方法执行..  
  7. 线程t3的method3方法执行完毕  
  8. 线程t3的method2调用结束  
  9. 线程t2的method1方法执行..  
  10. 线程t2的method2方法执行..  
  11. 线程t2的method3方法执行完毕  
  12. 线程t2的method2调用结束  
  13. 线程t2的method1调用结束  
线程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就执行不完了)。
         上面说的是一种锁重入的场景,锁重入还有一种常见的情形,那就是父子类的情况,再看一个例子

[html] view plain copy
print?
  1. package com.internet.thread;  
  2.   
  3. public class SyncDubbo2 {  
  4.     static class Main {  
  5.         public int i = 10;  
  6.         public synchronized void operationSup(){  
  7.             try {  
  8.                 i–;  
  9.                 System.out.println(“Main print i = ”+i);  
  10.                 Thread.sleep(100);//休息0.1秒  
  11.             } catch (Exception e) {  
  12.                 e.printStackTrace();  
  13.             }  
  14.         }  
  15.     }  
  16.       
  17.     static class Sub extends Main{  
  18.         public synchronized void operationSub(){  
  19.             try {  
  20.                 while(i > 0){  
  21.                     i–;  
  22.                     System.out.println(“Sub print i= ”+i);  
  23.                     Thread.sleep(100);  
  24.                     this.operationSup();  
  25.                 }  
  26.             } catch (Exception e) {  
  27.                 e.printStackTrace();  
  28.             }  
  29.         }  
  30.     }  
  31.       
  32.     public static void main(String[] args){  
  33.         Thread t1 = new Thread(new Runnable() {  
  34.               
  35.             @Override  
  36.             public void run() {  
  37.                 Sub sub = new Sub();  
  38.                 sub.operationSub();  
  39.             }  
  40.         });  
  41.         t1.start();  
  42.     }  
  43. }  
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修饰,说明父子类的情况锁重入也是可以的。

[html] view plain copy
print?
  1. Sub print i9  
  2. Main print i = 8  
  3. Sub print i7  
  4. Main print i = 6  
  5. Sub print i5  
  6. Main print i = 4  
  7. Sub print i3  
  8. Main print i = 2  
  9. Sub print i1  
  10. Main print i = 0  
Sub print i= 9Main print i = 8Sub print i= 7Main print i = 6Sub print i= 5Main print i = 4Sub print i= 3Main print i = 2Sub print i= 1Main print i = 0


使用Markdown编辑器写博客

本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦:

  • Markdown和扩展Markdown简洁的语法
  • 代码块高亮
  • 图片链接和图片上传
  • LaTex数学公式
  • UML序列图和流程图
  • 离线写博客
  • 导入导出Markdown文件
  • 丰富的快捷键

快捷键

  • 加粗 Ctrl + B
  • 斜体 Ctrl + I
  • 引用 Ctrl + Q
  • 插入链接 Ctrl + L
  • 插入代码 Ctrl + K
  • 插入图片 Ctrl + G
  • 提升标题 Ctrl + H
  • 有序列表 Ctrl + O
  • 无序列表 Ctrl + U
  • 横线 Ctrl + R
  • 撤销 Ctrl + Z
  • 重做 Ctrl + Y

Markdown及扩展

Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成格式丰富的HTML页面。 —— [ 维基百科 ]

使用简单的符号标识不同的标题,将某些文字标记为粗体或者斜体,创建一个链接等,详细语法参考帮助?。

本编辑器支持 Markdown Extra ,  扩展了很多好用的功能。具体请参考Github.

表格

Markdown Extra 表格语法:

项目 价格 Computer $1600 Phone $12 Pipe $1

可以使用冒号来定义对齐方式:

项目 价格 数量 Computer 1600 元 5 Phone 12 元 12 Pipe 1 元 234

定义列表

Markdown Extra 定义列表语法:
项目1
项目2
定义 A
定义 B
项目3
定义 C

定义 D

定义D内容

代码块

代码块语法遵循标准markdown代码,例如:

@requires_authorizationdef somefunc(param1='', param2=0):    '''A docstring'''    if param1 > param2: # interesting        print 'Greater'    return (param2 - param1 + 1) or Noneclass SomeClass:    pass>>> message = '''interpreter... prompt'''

脚注

生成一个脚注1.

目录

[TOC]来生成目录:

  • 欢迎
    • 快捷键
    • Markdown及扩展
      • 表格
      • 定义列表
      • 代码块
      • 脚注
      • 目录
      • 数学公式
      • UML 图
    • 离线写博客
    • 浏览器兼容

数学公式

使用MathJax渲染LaTex 数学公式,详见math.stackexchange.com.

  • 行内公式,数学公式为:Γ(n)=(n1)!nN
  • 块级公式:

x=b±b24ac2a

更多LaTex语法请参考 这儿.

UML 图:

可以渲染序列图:

Created with Raphaël 2.1.0张三张三李四李四嘿,小四儿, 写博客了没?李四愣了一下,说:忙得吐血,哪有时间写。

或者流程图:

Created with Raphaël 2.1.0开始我的操作确认?结束yesno
  • 关于 序列图 语法,参考 这儿,
  • 关于 流程图 语法,参考 这儿.

离线写博客

即使用户在没有网络的情况下,也可以通过本编辑器离线写博客(直接在曾经使用过的浏览器中输入write.blog.csdn.net/mdeditor即可。Markdown编辑器使用浏览器离线存储将内容保存在本地。

用户写博客的过程中,内容实时保存在浏览器缓存中,在用户关闭浏览器或者其它异常情况下,内容不会丢失。用户再次打开浏览器时,会显示上次用户正在编辑的没有发表的内容。

博客发表后,本地缓存将被删除。 

用户可以选择 把正在写的博客保存到服务器草稿箱,即使换浏览器或者清除缓存,内容也不会丢失。

注意:虽然浏览器存储大部分时候都比较可靠,但为了您的数据安全,在联网后,请务必及时发表或者保存到服务器草稿箱

浏览器兼容

  1. 目前,本编辑器对Chrome浏览器支持最为完整。建议大家使用较新版本的Chrome。
  2. IE9以下不支持
  3. IE9,10,11存在以下问题
    1. 不支持离线功能
    2. IE9不支持文件导入导出
    3. IE10不支持拖拽文件导入


  1. 这里是 脚注内容. ↩
原创粉丝点击