进程、线程、线程安全、线程池、死锁、多线程的总结框架

线程和进程

(由于我自己不知道怎么上传思维导图,想要思维导图的小伙伴,可以在评论区留邮箱,我看到了就会发送过去的)

进程和线程之间的区别

1 进程时资源分配的最小单位, 而线程时执行调度的最小单位

2 在一个进程中包含多个线程,线程共享该进程中的资源

3 进程要比线程消耗更多的计算机资源,一个线程挂掉将导致整个进程挂掉

进程

进程之间的通信方式

  • 互斥量:多个线程使用共享内存时,其他线程必须等待该线程技术该可以使用这块内存
  • 信号量:进程使用的内存地址可以限定使用量
  • 管道
  • 消息队列
  • 套接字

线程

创建线程的三种方式

  • 具体三种方式

    • 继承Thread类
    • 实现Runnable接口
    • 实现Callback接口和Futures接口
  • 三种方式对比

    • Thread类和两种接口方式的对比

      • 可以避免java单继承的限制

      • 线程池中只能存放又Runnable接口和Callable是接口实现的线程

        • 线程池

          • 线程池中概览

            • 线程池的创建

              • 创建线程池使用的主要函数以及对应的参数

                • public ThreadPoolExecutor(int corePoolSize, 核心线程数
                  -int maximumPoolSize, 最大线程数
                • long keepAliveTime, 非核心线程空闲时存活时间大小
                  -TimeUnit unit, 线程空闲时存活时间单位
                • BlockingQueue workQueue, 存放任务的工作队列也称阻塞队列
                • ThreadFactory threadFactory, 用户创建线程的工厂
                • RejectedExecutionHandler handler) 线程的拒绝策略
            • 线程池的执行流程

              • 图片链接:https://img-blog.csdn.net/20170618213838961?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTI0MDg3Nw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast
          • 线程池的四种拒绝策略

            • 抛出异常
            • 直接丢弃
            • 丢弃工作(阻塞)队列中最老的线程任务
            • 将控制权交给线程池调用的线程进行处理
          • 线程池五种工作队列

            • 有界队列(ArrayBlockingQueue): 使用数组来实现,按先进先出进行排序

            • 无界队列(LinkedBlockingQueue):可设置容量,使用链表来实现,最大的长度为Integer.maxValue,按先进先出排序。固定长度线程池(newFixedThreadPool)中使用的该类型的队列

              • 使用无界队列的线程池会导致内存飙升吗?

                • 会。如果线程获取一个任务以后,该任务执行时间很长,会导致无界队列内的任务越积越多,导致机器内存飙升
            • 延迟队列:任务定时延期执行的任务队列,定时周期性执行的线程池(newSechduledThreadPool)中使用该队列

            • 优先级队列:具有优先级的无界阻塞队列。

            • 同步队列:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用一处操作,否则插入操作一直处于阻塞状态。可缓存线程池(newCacheThreadPool)使用该队列

          • 线程池四种异常处理方式

            • 添加try…catch…finall块

                1. 在三个语句中都有return时,会执行什么内容
                1. finally永远执行除了以下几种情况
            • submit执行任务时,可以通过Future对象的get()方法接受抛出的异常,再进行处理

            • 为工作着的线程设置UncaughtExceptionHandler在该方法中处理异常

            • 重写ThreadPoolExecutor的afterExecute()方法处理传递异常引用

          • 常见的线程池以及使用场景

            • 固定长度线程池(newFixedThredPool)

              • 核心线程数=最大线程数
              • 使用无界阻塞队列
              • 使用场景:cpu密集型任务,执行长期任务
            • 定时周期性执行线程池(newSechduleThreadPool

              • 使用延迟队列
              • 使用场景:适用于周期性执行任务的场景
            • 可缓存线程池(newCacheThreadPool)

              • 使用同步线程池
              • 无核心线程
              • 使用场景:适用于并发执行大量短期的任务
            • 单线程的线程池(newSingletonThreadPool)

              • 最大线程数为1
              • 使用场景:适用于串行执行任务的场景
      • 适合多个线程进行资源共享

    • 两种接口方式的对比

      • 在Runnaable接口中调用的run()方法, Callable接口中调用的call()方法
      • 运行Callable可以拿到一个Future对象,表示异步计算得到的结果

线程调度

  • 抢占式线程调度
  • 协同式线程调度

线程的状态

  • 就绪(有执行资格,无执行权)

  • 运行(有执行资格,有执行权)

  • 阻塞(无执行资格,无执行权)

  • 终止

  • sleep()、await()、yield()的区别

    • sleep()是Object的方法,限期等待,可以执行阻塞多长时间,在线程的阻塞过程中,该线程不会释放锁,因此会造成其他也想访问该锁的线程进入阻塞的状态
    • await()是Thread的方法,进入阻塞状态以后,需要显示的调用notify()或则notifyAll()才能唤醒。该线程会释放锁
    • yield()同sleep()类似,只是不能像sleep()一样设置阻塞多长的时间。

线程不安全的原因

  • 共享资源的存在

线程安全的实现方式

  • 悲观锁

    • 定义:保证共享资源在同一时刻内只能被一个线程使用

    • Synchronize

      • 实现原理

        • Synchronize关键字经过编译以后,会在同步块前后形成monitorenter和moniterexist这两个字节码,这两个字节码都需要一个reference类型的参数来指明要锁定和解锁的对象。
      • Synchronize修饰方法时的加锁对象

        • 修饰静态方法,对类对象进行加锁

        • 修饰成员方法,对实例对象进行加锁

          • 多个线程访问同一对象的同一个方法

            • 因为一个对象只有一把锁,所以其他线程无法获取该对象的锁,就不能访问呢该对象的其他Synchronize修饰的方法
          • 多个线程作用于不同的对象

            • 不影响
        • 修饰代码块,对代码块内的对象进行加锁

      • Synchronize、ReentrLock、Lock之间的区别

        • Synchronize的缺点:可能会让等待中的锁一直无限期的等待下去,因为该锁只能由操作兄台那个自己释放,所以才产生了Lock
          1. Synchronize是JAVA的关键字,是内置语言,而Lock是一个接口
          1. Synchronize不需要手动去释放锁,由操作系统释放,而Lock需要调用unlock()函数进行手动的释放锁
          1. Lock的锁具有等待可中段的特性(也是得益于可手动释放锁),而Synchronize不行
          1. Lock可以知道有么有成功获取到锁,而Synchronize不可以
          1. Lock可以实现公平锁、可以在多个条件上加锁,而Synchronize不可以
        • 6 ReentreLock只是Lock的一个实现类
      • 对Synchronize锁的优化

        • 锁的开销是怎么产生的?

          • 由于竞争共享资源,需要操作系统内核对该线程进行阻塞以及唤醒,操作系统在这个过程中需要完成两次线程上下文切换。
            上下文切换:由于线程共享进程中的内存资源,因此只需要切换线程的私有数据、寄存器等不共享数据
        • 自旋锁

          • 拥有自旋锁的线程不会阻塞,而是自己执行几个忙循环
        • 轻量级锁

          • 在无实际竞争的环境下,减少重量级锁产生的性能消耗,仅仅_将Mark Word中的部分字节CAS更新指向线程栈中的Lock Record
        • 偏向锁

          • 减少无竞争且只有一个线程使用锁的情况下,产生的性能消耗
      • 生产者消费者模式手写代码

  • 乐观锁

    • 定义: 先默认不存在竞争共享资源的情况,运行所有任务,当出现竞争状态时,把发生了刚刚那条线程的执行操作进行抛弃。就是在线编辑文档一样

    • CAS

      • 实现原理

        • pos=A,将B赋值给变量pos
      • ABA问题的解决方法

        • JDK的atomic包里提供了一个类AtomicStampedReference来解决ABA问题。如果当前引用 == 预期引用,并且当前标志等于预期标志,则以原子方式将该引用和该标志的值设置为给定的更新值。
      • 实现一个线程安全的计数器

        • 使用java.util.concurrent.atomic.AtomicInteger来定义变量
          然后使用IncrementAndGet()来实现自增
  • 使用final关键字

  • ThreadLocal

    • 定义

      • 由ThreadLocal修饰的对象,在不同的线程中有自己的副本
    • 实现原理

      • 在ThreadLocal内部维护了一个ThreadLocalMap。{key:实例对象;value:变量}
    • 存在内存泄露问题,怎么解决

      • 为什么存在内存泄漏问题?
        因为ThreadLocalMap中的key是弱引用,因此当在经过一次gc以后,就会对该key进行回收。这时就会出现key为null,而value继续存在,因此出现内存泄漏
      • 解决方案:
        使用完ThreadLocal就进行remove()操作

死锁

  • 定义

    • 多个线程循环等待它方占有资源,而陷入无限期等待的情况
  • 四个必要条件

    • 互斥性
    • 不可抢占性
    • 循环等待
    • 占有且申请
  • 怎么避免死锁

    • 打破互斥性的条件
    • 打破不可抢占的条件
    • 打破占有且申请的条件,采用资源预先分配的方法
    • 打破循环等待的条件,采用资源有序分配的方法

多线程—深入理解AQS抽象队列同步器

  • AQS框架

    • ReentranLock

      • 实现自Lock接口,具有可重入性,能够对资源进行重复加锁。
    • ReentranReadWriteLock

      • 表示两个锁,一个是读操作相关的共享锁,一个写操作相关的排他锁
    • CountDownLatch

      • 四个线程ABCD,其中D线程要等到ABC全部执行完毕以后才执行
        1. 创建一个计数器,设置初始值:CountDownLatch c = new CountDownLatch(number)
        1. 在等待线程D中调用CountDownLatch.await(),进入等待状态,直到计数值变为0
        1. 在其他线程中调用CountDownLatch.countDown()方法,该方法会把计数值递减
        1. 当其他线程中的countDown()方法把计数值变为0时,等待线程中的CountDownLatch.await()立即退出,执行接下去的代码
    • CyclicBarrier

      • 三个运动员各自准备,等三个人准备后一次性跑
        1. 创建一个公共的 CyclicBarrier对象:设置同时等待的线程数
          CyclicBarrier cb = new CyclicBarrier(number)
        1. 这些线程同时开始自己的准备,自身准备完以后,需要等待别人准备完毕,这是调用cb.await(),开始等待别人
        1. 当指定的同时等待线程数都调用了cb.await()时,意味着这些线程都准备好了,然后可以同时执行
    • Semaphore

      • 可以控制同时访问的线程的个数,通过acquire()获得一个许可,通过release()释放一个许可

java.util.concurrent中都提供了哪些基础并发工具类

  • 可丰富多线程操作的类

    • CountDownLatch
    • CylicBarrier
    • Semaphore
    • 比Synchronize更加高级的同步结构
  • 线程安全的容器

    • ConcurrentHashMap
    • CopyOnWriteArrayList
  • 并发队列

    • BlockQueue的实现
    • ArrayBlockQueue
  • 强大的Executor框架

    • 固定长度线程池
    • 可缓存线程池
    • 单线程线程池
    • 周期执行线程池
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值