架构师养成记--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

 

posted on 2016-12-01 23:39  司广孟  阅读(823)  评论(0编辑  收藏  举报

导航