zoukankan      html  css  js  c++  java
  • 架构师养成记--3.synchronized细节问题

    一、synchronized有锁重入的特点,某个线程得到对象的锁后,再次请求此对象可以再次得到改对象的锁。如下示例,在method1中调用method2,在method2中调用method3,而method1、method2和method3都是加了synchronized关键字的。

     1 /**
     2  * synchronized的重入
     3  * @author alienware
     4  *
     5  */
     6 public class SyncDubbo1 {
     7 
     8     public synchronized void method1(){
     9         System.out.println("method1..");
    10         method2();
    11     }
    12     public synchronized void method2(){
    13         System.out.println("method2..");
    14         method3();
    15     }
    16     public synchronized void method3(){
    17         System.out.println("method3..");
    18     }
    19     
    20     public static void main(String[] args) {
    21         final SyncDubbo1 sd = new SyncDubbo1();
    22         Thread t1 = new Thread(new Runnable() {
    23             @Override
    24             public void run() {
    25                 sd.method1();
    26             }
    27         });
    28         t1.start();
    29     }
    30 }

    二、父类和子类的方法都是synchronized的,在子类的方法中调用父类的方法,也是线程安全的。

     1 /**
     2  * synchronized的重入
     3  * @author alienware
     4  *
     5  */
     6 public class SyncDubbo2 {
     7 
     8     static class Main {
     9         public int i = 10;
    10         public synchronized void operationSup(){
    11             try {
    12                 i--;
    13                 System.out.println("Main print i = " + i);
    14                 Thread.sleep(100);
    15             } catch (InterruptedException e) {
    16                 e.printStackTrace();
    17             }
    18         }
    19     }
    20     
    21     static class Sub extends Main {
    22         public synchronized void operationSub(){
    23             try {
    24                 while(i > 0) {
    25                     i--;
    26                     System.out.println("Sub print i = " + i);
    27                     Thread.sleep(100);        
    28                     this.operationSup();
    29                 }
    30             } catch (InterruptedException e) {
    31                 e.printStackTrace();
    32             }
    33         }
    34     }
    35     
    36     public static void main(String[] args) {
    37         
    38         Thread t1 = new Thread(new Runnable() {
    39             @Override
    40             public void run() {
    41                 Sub sub = new Sub();
    42                 sub.operationSub();
    43             }
    44         });
    45         
    46         t1.start();
    47     }
    48     
    49     
    50 }

    执行结果:

     

    三、synchronized方法内抛异常怎么处理

      throw RuntimeException打断此线程或者记录日志然后continue,选择哪种方案取决于具体业务要求。

     1 /**
     2  * synchronized异常
     3  * @author alienware
     4  *
     5  */
     6 public class SyncException {
     7 
     8     private int i = 0;
     9     public synchronized void operation(){
    10         while(true){
    11             try {
    12                 i++;
    13                 Thread.sleep(100);
    14                 System.out.println(Thread.currentThread().getName() + " , i = " + i);
    15                 if(i == 20){
    16                     //Integer.parseInt("a");
    17                     throw new RuntimeException();
    18                 }
    19             } catch (InterruptedException e) {
    20                 e.printStackTrace();
    21             }
    22         }
    23     }
    24     
    25     public static void main(String[] args) {
    26         
    27         final SyncException se = new SyncException();
    28         Thread t1 = new Thread(new Runnable() {
    29             @Override
    30             public void run() {
    31                 se.operation();
    32             }
    33         },"t1");
    34         t1.start();
    35     }
    36     
    37     
    38 }

     四、synchronized代码块锁,实用起来也会比较灵活

      this、class、Object都可以用来作为代码块锁

     1 /**
     2  * 使用synchronized代码块加锁,比较灵活
     3  * @author alienware
     4  *
     5  */
     6 public class ObjectLock {
     7 
     8     public void method1(){
     9         synchronized (this) {    //对象锁
    10             try {
    11                 System.out.println("do method1..");
    12                 Thread.sleep(2000);
    13             } catch (InterruptedException e) {
    14                 e.printStackTrace();
    15             }
    16         }
    17     }
    18     
    19     public void method2(){        //类锁
    20         synchronized (ObjectLock.class) {
    21             try {
    22                 System.out.println("do method2..");
    23                 Thread.sleep(2000);
    24             } catch (InterruptedException e) {
    25                 e.printStackTrace();
    26             }
    27         }
    28     }
    29     
    30     private Object lock = new Object();
    31     public void method3(){        //任何对象锁
    32         synchronized (lock) {
    33             try {
    34                 System.out.println("do method3..");
    35                 Thread.sleep(2000);
    36             } catch (InterruptedException e) {
    37                 e.printStackTrace();
    38             }
    39         }
    40     }
    41     
    42     
    43     public static void main(String[] args) {
    44         
    45         final ObjectLock objLock = new ObjectLock();
    46         Thread t1 = new Thread(new Runnable() {
    47             @Override
    48             public void run() {
    49                 objLock.method1();
    50             }
    51         });
    52         Thread t2 = new Thread(new Runnable() {
    53             @Override
    54             public void run() {
    55                 objLock.method2();
    56             }
    57         });
    58         Thread t3 = new Thread(new Runnable() {
    59             @Override
    60             public void run() {
    61                 objLock.method3();
    62             }
    63         });
    64         
    65         t1.start();
    66         t2.start();
    67         t3.start();
    68         
    69         
    70     }
    71     
    72 }
    View Code

    五、尽量不要用String常量作为锁

    如下代码只会有t1线程运行,但可以new一个String对象。

     1 /**
     2  * synchronized代码块对字符串的锁,注意String常量池的缓存功能
     3  * @author alienware
     4  *
     5  */
     6 public class StringLock {
     7 
     8     public void method() {
     9         //new String("字符串常量")
    10         synchronized ("字符串常量") {
    11             try {
    12                 while(true){
    13                     System.out.println("当前线程 : "  + Thread.currentThread().getName() + "开始");
    14                     Thread.sleep(1000);        
    15                     System.out.println("当前线程 : "  + Thread.currentThread().getName() + "结束");
    16                 }
    17             } catch (InterruptedException e) {
    18                 e.printStackTrace();
    19             }
    20         }
    21     }
    22     
    23     public static void main(String[] args) {
    24         final StringLock stringLock = new StringLock();
    25         Thread t1 = new Thread(new Runnable() {
    26             @Override
    27             public void run() {
    28                 stringLock.method();
    29             }
    30         },"t1");
    31         Thread t2 = new Thread(new Runnable() {
    32             @Override
    33             public void run() {
    34                 stringLock.method();
    35             }
    36         },"t2");
    37         
    38         t1.start();
    39         t2.start();
    40     }
    41 }
    View Code

    六、一个对象被用作锁时,这个对象内的属性发生变化不会影响锁的使用。

     1 /**
     2  * 同一对象属性的修改不会影响锁的情况
     3  * @author alienware
     4  *
     5  */
     6 public class ModifyLock {
     7     
     8     private String name ;
     9     private int age ;
    10     
    11     public String getName() {
    12         return name;
    13     }
    14     public void setName(String name) {
    15         this.name = name;
    16     }
    17     public int getAge() {
    18         return age;
    19     }
    20     public void setAge(int age) {
    21         this.age = age;
    22     }
    23     
    24     public synchronized void changeAttributte(String name, int age) {
    25         try {
    26             System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 开始");
    27             this.setName(name);
    28             this.setAge(age);
    29             
    30             System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 修改对象内容为: " 
    31                     + this.getName() + ", " + this.getAge());
    32             
    33             Thread.sleep(2000);
    34             System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 结束");
    35         } catch (InterruptedException e) {
    36             e.printStackTrace();
    37         }
    38     }
    39     
    40     public static void main(String[] args) {
    41         final ModifyLock modifyLock = new ModifyLock();
    42         Thread t1 = new Thread(new Runnable() {
    43             @Override
    44             public void run() {
    45                 modifyLock.changeAttributte("张三", 20);
    46             }
    47         },"t1");
    48         Thread t2 = new Thread(new Runnable() {
    49             @Override
    50             public void run() {
    51                 modifyLock.changeAttributte("李四", 21);
    52             }
    53         },"t2");
    54         
    55         t1.start();
    56         try {
    57             Thread.sleep(100);
    58         } catch (InterruptedException e) {
    59             e.printStackTrace();
    60         }
    61         t2.start();
    62     }
    63     
    64 }
    View Code
  • 相关阅读:
    大型网站架构之分布式消息队列【转】
    Jpa生成mysql注释,添加ODBC数据源导入数据到EA
    Spring boot框架项目,使用maven命令将配置文件打包到jar包外,项目运行读取jar外配置文件
    spring boot 整合 quartz 集群环境 实现 动态定时任务配置【原】
    关于博主
    [School Life] 骗你去努力
    [OI
    洛谷P4994【终于结束的起点】
    [OI系列]在考场千万不能犯的错误
    [OI
  • 原文地址:https://www.cnblogs.com/sigm/p/6124079.html
Copyright © 2011-2022 走看看