zoukankan      html  css  js  c++  java
  • Java

    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. 他们会 同时 执行 相同 或者 不同 的任务
            1. 表面上的同时
      2. 问题

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

          1. CPU 消耗增加

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

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

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

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

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

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

            1. 竞态条件(race condition) - 这翻译我总觉得怪怪的...

              1. 多个线程争夺相同资源的使用
              2. 但是 线程调度 的不可预测
              3. 于是, 会导致下列情况
            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. 以及其他一些工具类
            3. 通过为线程的执行, 添加各种 前置状态, 来间接限定线程的执行顺序
        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 段, 不会被别的线程打断
            2. 因为不会被打断, 避免了执行中因为 线程调度, 而导致 数据出现类似 脏读, 不可重复读, 幻读 之类的隔离性问题
    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. 类中没有被 synchronized 关键字修饰的代码, 不会受到影响
      2. 可以允许多个 线程 同时, 不同步的执行

    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. 如何处理 死锁
      5. volatile
      6. Java 内存模型
        1. 这玩意竟然是 描述多线程情况下, 线程可以对 主存 所作的事
        2. Java 语言规范
  • 相关阅读:
    .NET 世界中的远程脚本
    操作Active Directory C#
    三层体系结构总结(四)
    C#+Asp.net系列教程
    勿重复检测浏览器
    事件模块的演变(8)
    读jQuery之三(构建选择器)
    读jQuery之二(两种扩展)
    新API解析JSONAjax之七
    JS Queue LazyLoad 之二
  • 原文地址:https://www.cnblogs.com/xy14/p/12893432.html
Copyright © 2011-2022 走看看