并发编程(三)—— synchronized

一、synchronized锁重入

1. 概念

关键字synchronized拥有锁重入的功能,也就是在使用synchronized时,当一个线程得到了一个对象的锁后,再次请求此对象时是可以再次得到此对象的锁。

2. 示例

【com.xxy.base.sync005.SyncDubbo1】

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

 

【com.xxy.base.sync005.SyncDubbo2】

 1 package com.xxy.base.sync005;
 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);
11             } catch (InterruptedException e) {
12                 // TODO Auto-generated catch block
13                 e.printStackTrace();
14             }
15         }
16     }
17     
18     static class Sub extends Main{
19         public synchronized void operationSub() {
20             try {
21                 while(i > 0) {
22                     i--;
23                     System.out.println("Sub print i = " + i);
24                     Thread.sleep(100);
25                     this.operationSup();
26                 }
27             } catch (InterruptedException e) {
28                 // TODO Auto-generated catch block
29                 e.printStackTrace();
30             }
31         }
32     }
33     
34     public static void main(String[] args) {
35         Thread t1 = new Thread(new Runnable() {
36             
37             @Override
38             public void run() {
39                 Sub sub = new Sub();
40                 sub.operationSub();
41             }
42         });
43         
44         t1.start();
45     }
46 }
View Code

 

3. 出现异常,锁自动释放,示例:【com.xxy.base.sync005.SyncException】

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

 

4. 说明

对于web应用程序,异常释放锁的情况,如果不及时处理,很可能对你的应用程序业务逻辑产生严重的错误,比如你现在执行一个队列任务,很多对象都去在等待第一个对象正确执行完毕再去释放锁,但是第一个对象由于异常的出现,导致业务逻辑没有正常执行完毕,就释放了锁,那么可想而知后续的对象执行的都是错误的逻辑。所以,这一点一定要引起注意,在编写代码的时候一定要考虑周全。

 

二、synchronized代码块

1. 介绍

使用synchronized声明的方法在某些情况下是有弊端的,比如A线程调用同步的方法执行一个很长时间的任务,那么B线程就必须等待比较长的时间才能执行,这样的情况下可以使用synchronized代码块去优化代码执行时间,也就是通常所说的减小锁粒度。

示例:【com.xxy.base.sync006 Optimize】

 

2. synchronized可以使用任意的Object进行加锁,用法比较灵活。

示例:【com.xxy.base.sync006 ObjectLock】

 

3.另外特别注意一个问题,就是不要使用String的常量加锁,会出现死循环问题

示例:【com.xxy.base.sync006 StringLock】

 

4.锁对象的改变问题,当使用一个对象进行加锁的时候,要注意对象本身发生改变的时候,那么持有的锁就不同。如果对象本身不发生改变,那么依然是同步的,即使是对象的属性发生了改变。

示例:【com.xxy.base.sync006 ChangeLock ModifyLock】

 

5.死锁问题

示例:【com.xxy.base.sync006 DeadLock】

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2020-09-22 23:08  海边拾贝seebit  阅读(128)  评论(0编辑  收藏  举报