首页 > 编程语言 >编程规约-并发处理-锁

编程规约-并发处理-锁

时间:2022-09-23 20:59:09浏览次数:50  
标签:加锁 helper 规约 lock 代码 编程 try 并发 finally

编程规约-并发处理-锁

考量锁的性能损耗

高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁。

说明:尽可能使加锁的代码块工作量尽可能的小,避免在锁代码块中调用 RPC 方法。

保持一致的加锁顺序

对多个资源、数据库表、对象同时加锁时,需要保持一致的加锁顺序,否则可能会造成死锁。

说明:线程一需要对表 A、B、C 依次全部加锁后才可以进行更新操作,那么线程二的加锁顺序也必须是 A、B、C,否则可能出现死锁。

加锁方法

加锁方法与 try 代码块之间 没有异常可能

在使用阻塞等待获取锁的方式中,必须在 try 代码块之外,并且在加锁方法与 try 代码块之间没有任何可能抛出异常的方法调用,避免加锁成功后,在 finally 中无法解锁。

说明一:如果在 lock 方法与 try 代码块之间的方法调用抛出异常,那么无法解锁,造成其它线程无法成功获取锁。

说明二:如果 lock 方法在 try 代码块之内,可能由于其它方法抛出异常,导致在 finally 代码块中,unlock 对未加锁的对象解锁,它会调用 AQS 的 tryRelease 方法(取决于具体实现类),抛出 IllegalMonitorStateException 异常。

说明三:在 Lock 对象的 lock 方法实现中可能抛出 unchecked 异常,产生的后果与说明二相同。

正例:

Lock lock = new XxxLock();
// ...
lock.lock();
try {
    doSomething();
    doOthers();
} finally {
    lock.unlock();
}

反例:

Lock lock = new XxxLock();
// ...
try {
    // 如果此处抛出异常,则直接执行 finally 代码块
    doSomething();
    // 无论加锁是否成功,finally 代码块都会执行
    lock.lock();
    doOthers();
} finally {
    lock.unlock();
}

尝试机制来获取锁 先判断是否持有锁

在使用尝试机制来获取锁的方式中,进入业务代码块之前,必须先判断当前线程是否持有锁。锁的释放规则与锁的阻塞等待方式相同。

说明:Lock 对象的 unlock 方法在执行时,它会调用 AQS 的 tryRelease 方法(取决于具体实现类),如果当前线程不持有锁,则抛出 IllegalMonitorStateException 异常。

正例:

Lock lock = new XxxLock();
// ...
boolean isLocked = lock.tryLock();
if (isLocked) {
    try {
        doSomething();
        doOthers();
    } finally {
        lock.unlock();
    } 
}

乐观锁与悲观锁

使用乐观锁与悲观锁

并发修改同一记录时,避免更新丢失,需要加锁。要么在应用层加锁,要么在缓存加锁,要么在数据库层使用乐观锁,使用 version 作为更新依据。

说明:如果每次访问冲突概率小于 20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得小于3 次。

资金相关的金融敏感信息,使用悲观锁策略。

说明:乐观锁在获得锁的同时已经完成了更新操作,校验逻辑容易出现漏洞,另外,乐观锁对冲突的解决策略有较复杂的要求,处理不当容易造成系统压力或数据异常,所以资金相关的金融敏感信息不建议使用乐观锁更新。

正例:悲观锁遵循一锁、二判、三更新、四释放的原则。

双重检查锁

双重检查锁存在的隐患

通过双重检查锁(double-checked locking)(在并发场景下)存在延迟初始化的优化问题隐患(可参考 The "Double-Checked Locking is Broken" Declaration)。

推荐解决方案中较为简单一种(适用于 JDK5 及以上版本),将目标属性声明为 volatile 型,比如将 helper 的属性声明修改为private volatile Helper helper = null;

正例:

package com.gcbeen.concurrent;

public class LazyInitDemo {
    private volatile Helper helper = null;

    public Helper getHelper() {
        // 双重检查锁
        if (helper == null) {
            synchronized (this) {
                if (helper == null) {
                    helper = new Helper();
                }
            }
        }
        return helper;
    }
  // other methods and fields...
}

标签:加锁,helper,规约,lock,代码,编程,try,并发,finally
From: https://www.cnblogs.com/gcbeen/p/16724182.html

相关文章

  • 编程规约-并发处理
    编程规约-并发处理线程安全保证线程安全获取单例对象需要保证线程安全,其中的方法也要保证线程安全。说明:资源驱动类、工具类、单例工厂类都需要注意。SimpleDateForma......
  • 编程规约-集合处理
    编程规约-集合处理泛型集合泛型定义集合泛型定义时,在JDK7及以上,使用diamond语法或全省略。说明:菱形泛型,即diamond,直接使用<>来指代前边已经指定的类型。正例://......
  • 编程规约-处理Map List Set
    编程规约-处理MapListSetMapCollectors类的toMap()方法相同键相关联的值之间的冲突在使用java.util.stream.Collectors类的toMap()方法转为Map集合时,一定要使......
  • 编程语言界的丐帮 C#.NET FRAMEWORK 4.6 EF 连接MYSQL
    1.nuget引用 EntityFramework、和 MySql.Data.EntityFramework。  MySql.Data这个库视情况。2.新建实体类:usingSystem;usingSystem.ComponentModel.DataAnnot......
  • 编程小知识
    在编程的过程中总会遇到各种各样的小问题,问题虽然不大,有时候也很头疼,在这里有个小小的记录python之PEP8规范在使用pycharm过程中,有时候代码会突然出现红色或者黄色的波......
  • 面向对象编程(OOP)与面向过程编程(POP)
    面向对象编程(OOP)与面向过程编程(POP)10个主要区别面向对象编程(OOP)和面向过程编程(POP)之间的关系。大家好,今天我要讲的10个主要区别面向对象编程(OOP)和面向过程编程(POP)之......
  • Java并发之ReentrantLock基础(一)
    ReentrantLock是Java中java.util.concurrent.locks.Lock的一个实现类,顾名思义它是Java中锁的一种实现,具体一点来说它是Java中一种可重入的独占锁。它与synchronized相比在......
  • 结对编程评价对方
    本次结对编程我和杨锐坚一对。 过程中,对方认真负责,帮助我纠正了不少代码规范问题。 在关于页面跳转的实现方式中提出了比较规范的方法:自定义的页面对象继承SWING中的......
  • 快速上手React编程 pdf
    高清扫描版下载链接:https://pan.baidu.com/s/1R4B-izNpESydo-yFNmU8xw点击这里获取提取码 ......
  • 【Springboot之切面编程】自定义注解实现入参指定枚举值校验
    通过自定义枚举注解@EnumValidator(value=SexEnums.class),privateIntegersex;就可以校验入参值必须在指定枚举类中原创:https://www.jianshu.com/p/32f0d6e3afbb......