首页 > 编程语言 > 详细

Java - JVM - synchronized

时间:2020-05-15 11:04:37      阅读:39      评论:0      收藏:0      [点我收藏+]
  1. 概述

    1. 简单聊聊这个 关键字
  2. 背景

    1. 最近整理到了 jvm 的线程, 然后就开始整理到了 jvm 并发相关的内容
      1. 老实说, 这块之前确实没有学好, 挖了一个大坑
      2. 碰见坑就填吧, 慢慢填, 一点一点填好

1. 单线程的问题, 与多线程的引入

  1. 概述

    1. 单线程的问题
    2. 多线程的引入
  2. 单线程的问题

    1. 单线程

      1. 一个线程执行程序
        1. 所有的执行都是 序列化
          1. 有章可循, 逻辑清晰
    2. 问题

      1. 当硬件上来时, 单线程无法全部发挥硬件的效果

        1. CPU 有能力处理多个线程时, 只处理多线程, 会浪费算力
          1. 但是从另一个角度来说, 也会限制程序的 处理能力
        2. 内存 扩大时, JVM 可以容纳更多的 栈
        3. I/O 规模扩大时, 单线程需要 wait 或者 sleep, 也没有好好发挥资源
          1. 这个后面再说
          2. 简单的说, 就是 IO 的时候, 这个线程通常只能等着, 啥也干不了
          3. 其实可以异步, 但这个暂时不提
      2. 单线程对 用户 来说, 不够友好

        1. 一个线程如果要处理数据, 则 UI 的响应, 肯定会很慢
      3. 容易崩溃

        1. 单线程 的程序来说, 一个线程崩溃, 整个程序就挂掉了
          1. 多线程还可以想办法抢救一下...
  3. 问题的解决

    1. 当然是 引入多线程 啦
      1. 其实从 Thread 类来看, jdk1.0 就已经引入了

2. 多线程的问题

  1. 概述

    1. 多线程的问题
  2. 多线程的问题

    1. 多线程

      1. 一个进程内, 有多个线程
        1. 他们会执行 相同 或者 不同 的任务
    2. 问题

      1. 硬件消耗增加, 但是如果控制得当, 则未必是坏事

        1. CPU 消耗增加

          1. 提高了 CPU 的利用率
          2. 也能提高 程序处理数据的能力
        2. 内存占用大

          1. 高了内存的占用率
        3. I/O 占用大

          1. 高了 I/O 效率
        4. 线程的 创建 和 切换, 会消耗额外的资源

          1. 没关系, 相比线程带来的好处, 这些都是毛毛雨
      2. 线程调度, 这是一个新的问题

        1. 如何确定什么时候, 该执行什么线程

          1. jvm 的线程调度, 这个以后有机会再说
        2. 竞态条件

          1. 多个线程对同一个资源有需求

            1. 但是 线程切换 的不可预测, 又会导致下列情况
          2. 非原子操作中, 线程被中断, 会怎么办?

            1. 例如: a += 1
              1. 这个操作不是原子性的, 需要 取出; 加1; 赋值 三个步骤
              2. 如果在这中途中断了, 就会导致后续程序出现问题
              3. 而且通常情况下, 你无法确定
          3. 某个流程中, 线程被中断, 怎么办

            1. 常见的例子, 就是那个 取钱 的例子
            2. 例子都举烂了, 我就不说了
          4. 出现了死锁, 又怎么办?

            1. 场景
              1. 两个线程, 需要同样的资源
              2. 需要同时持有 资源A 和 资源B 才能办事
              3. 资源A 和 资源B 只有一份
              4. 线程持有资源后, 不会主动释放
              5. 于是可能会出现一个场景: 线程1 持有A, 线程2 持有B, 然后卡死不动
  3. 解决

    1. 硬件问题

      1. 不是大问题
    2. 调度问题

      1. jvm 的调度顺序, 通常来说不可预知

        1. 同样的程序, 通常每次执行的顺序, 都会不一样
        2. 试着把没有顺序的东西, 变得有顺序
          1. 依靠 同步, 等待, 唤醒
          2. 以及其他一些工具类
      2. 非原子操作

        1. 这个通过 volatile 来解决
          1. 作用有限
          2. 线程调度导致的 流程中断, 是没办法通过这个来解决的
      3. 流程中断

        1. 这个通过 synchronized 关键字解决
      4. 死锁的通常解决方案

        1. 确定线程的获取顺序
        2. 如果持有资源但长时间无法工作, 则放弃资源重新等待获取
        3. 这个后面会有机会会说...

3. sychronized

  1. 概述

    1. synchronized
  2. 数据库事务的四个特性

    1. 概述

      1. 怎么想起了这玩意
    2. ACID

      1. 原子性
      2. 一致性
      3. 隔离性
      4. 持久性
    3. synchronized 解决的问题

      1. 主要还是 流程中断 的问题
        1. 原子性
          1. synchronized 可以让一个线程把 某个小片段 执行完整
            1. 当然有个前提, 是中途不出异常
            2. 所以这个原子性, 算是能解决一半吧
            3. 出现异常的回退, 就需要自己实现了
        2. 隔离性
          1. 线程在 synchronized 段, 不会被别的线程打断
  3. 用法

    1. synchronized 方法

      1. 使用

        1. 通过 synchronized 关键字, 来修饰方法

          public static synchronized void method() {}
          public synchronized void method() {}
          
      2. 分类

        1. 修饰 静态方法

          1. 由 Class对象 的锁, 来保证 原子性 与 隔离性
            1. 同一时间, 只有抢到 监视器锁 的线程, 可以执行这段代码
            2. 没有抢到的, 需要等待锁释放
        2. 修饰 实例方法

          1. 由 实例对象 的锁, 来保证 原子性 与 隔离性
            1. 同 修饰静态方法
      3. 问题

        1. 无法手工制定 锁

          1. 锁 是跟随 对象的
            1. 每个对象会有一个 监视器锁
            2. synchronized 方法的锁, 是指定了无法修改
        2. 粒度太粗

          1. 部分 synchronized 方法里, 只有一小段代码需要
            1. 如果 限定整个方法, 就会引起阻塞
    2. synchronized 代码块

      1. 使用

        1. 使用 synchronized 修饰代码块

          synchronized(obj) {}
          
      2. obj

        1. 这个是一个特定的对象
          1. 线程争抢的锁, 就是 这个 obj 的 监视器锁

4. 等等, 好像又有一个问题

  1. 概述

    1. 好像又有一个问题
  2. 场景

    1. 角色

      1. 资源 S
      2. 对象 O1, O2
      3. 线程 T1, T2, T3
    2. 场景

      1. 对象 O1 持有 S

        1. O1 在 synchronized 代码块里, 操作 S
        2. T1 和 T2 轮流访问 O1 的 synchronized 代码块
        3. 看上去好像很正常的样子
      2. 对象 O2, 也持有 S

        1. T3 通过 O2 来访问 S
        2. O1 的同步代码块, 好像就管不着这个玩意了...
    3. 我的感觉

      1. 这样的场景下, 依然会出现很多 匪夷所思, 无法预料到结果...

ps

  1. ref

    1. Java 语言规范(Java SE 8)
    2. Java 编程思想(第四版)
    3. Java 核心技术(第十版)
  2. 后续

    1. 线程调度
    2. 监视器锁 与 等待队列
    3. 线程状态
    4. 如何处理 死锁

Java - JVM - synchronized

原文:https://www.cnblogs.com/xy14/p/12893432.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!