• Java多线程-----线程安全


    什么是线程安全

    连个线程同时操作同一个公共资源,容易造成资源错误

    加入两个人代表两个线程他俩同时去取钱10元,但是账户只有10元,如果不处理线程安全容易造成两人都能取出来钱; 

    一,线程同步

    解决线程安全-----加锁

    让多个线程先后依次的访问共享资源


    1,同步代码块

    作用访问共享资源的核心代码给上锁,以此保证线程安全。

    原理每次只允许一个线程加锁后进入执行完毕后自动解锁,其他线程才可以进来执行

    • 实现同步代码块

      • 选中共享资源的代码CTRL+T  然后选中 synchronized
        1. //锁对象:必须是一个唯一的对象(同一个地址)锁对象可以是任何对象甚至是字符串
        2. synchronized(锁对象){
        3. //...访问共享数据的代码...
        4. }

    • 对于静态方法建议使用字节码(类名.class对象作为锁对象。
        1. public static void test(){
        2. synchronized(类名.class){
        3. }
        4. }
    • 建议使用共享资源作为锁对象,对于实例方法建议使用this作为锁对象。
      • this 代表着是共享账户
        1. public void test(){
        2. synchronized(this){
        3. }
        4. }

     2,同步方法

    将处理共享资源的方法上加上 syschronized 关键字 表示当前是一个同步方法

    1. public synchronized void drawMoney(double money) {
    2.     // 先搞清楚是谁来取钱?
    3.     String name = Thread.currentThread().getName();
    4.     // 1、判断余额是否足够
    5.     if(this.money >= money){
    6.         System.out.println(name + "来取钱" + money + "成功!");
    7.         this.money -= money;
    8.         System.out.println(name + "来取钱后,余额剩余:" + this.money);
    9.     }else {
    10.         System.out.println(name + "来取钱:余额不足~");
    11.     }
    12. }
    • 如果是实例方法默认使用this作为锁对象
    • 如果是静态方法默认使用类名.class作为锁对象
    • 底层原理:
      • 同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法代码

    同步代码块和同步方法的区别

    范围上:同步代码块锁的范围更小,同步方法锁的范围更大

    可读性:同步方法更好

    3,Lock锁 

    • 怎么实现

      • 创建锁对象,放在方法外面,表示这个是当前对象的锁  加上final修饰表示当前锁无法被修改
        1. // 创建了一个锁对象
        2. private final Lock lk = new ReentrantLock();
      • 在方法内部需要加锁的地方加锁
      • 在需要的地方进行解锁
      • 以上两步一般使用try-catch-finally修饰,以防中间代码出现问题也能进行解锁

    实现Lock锁

    1. // 创建了一个锁对象
    2. private final Lock lk = new ReentrantLock();
    3. public void drawMoney(double money) {
    4. // 先搞清楚是谁来取钱?
    5. String name = Thread.currentThread().getName();
    6. try {
    7. lk.lock(); // 加锁
    8. // 1、判断余额是否足够
    9. if(this.money >= money){
    10. System.out.println(name + "来取钱" + money + "成功!");
    11. this.money -= money;
    12. System.out.println(name + "来取钱后,余额剩余:" + this.money);
    13. }else {
    14. System.out.println(name + "来取钱:余额不足~");
    15. }
    16. } catch (Exception e) {
    17. e.printStackTrace();
    18. } finally {
    19. lk.unlock(); // 解锁
    20. }
    21. }
    22. }

    注意: 

    同一个锁对象可以跨方法锁住多个方法

  • 相关阅读:
    [极客大挑战 2019]PHP1
    《Java基础知识》Java transient关键字详解
    ArrayDeque详解(含动画演示)
    SSM的整合
    (三)Mybatis------引入Mapper接口以及传入各种参数类型
    BMS电池管理系统——BMS的功能模块及基本要素(二)
    栈(顺序栈)实现Language C
    C++ 模板进阶
    RocketMQ和Kafka到底选哪个
    【优化算法】多目标晶体结构算法算法(Matlab代码实现)
  • 原文地址:https://blog.csdn.net/qq_57667629/article/details/134321632