• 并发编程(三)—— 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】

  • 相关阅读:
    树莓派学习笔记(三)——远程调试树莓派程序(Pycharm实现)
    树莓派学习笔记(一)——系统安装与远程显示
    记 laravel 排除CSRF验证
    thinkPHP5 生成微信小程序二维码 保存在本地
    微信小程序 rich-text 富文本中图片自适应
    Laravel 中自定义 手机号和身份证号验证
    laravel Excel 导入
    微信小程序之页面跳转(tabbar跳转及页面内跳转)
    关于MySQL事务和存储引擎常见FAQ
    微信小程序点击保存图片到本地相册——踩坑
  • 原文地址:https://www.cnblogs.com/upyang/p/13668895.html
Copyright © 2020-2023  润新知