JUC1 线程基础概念

0. 为什么使用多线程及其重要


摩尔定律失效(硬件方面):
(1). 集成电路上可以容纳的晶体管数目在大约每经过18个月便会增加一倍,可是从2003年开始CPU主频已经不再翻倍,而是采用多核而不是更快的主频
(2). 在主频不再提高且核数不断增加的情况下,要想让程序更快就要用到并行或并发编程高并发系统,异步+回调的生产需求(软件方面)
 

1. java多线程的概念

1把锁:synchronize

2个并:

并发(cocurrent):一个处理器多个任务,做同一个事情

并行(parrallel):多个处理器多个任务,做不同事情

3个程:

进程:系统运行的一个应用程序

线程:轻量级进程

管程:Monitor 监视器,即锁

2. 用户线程和守护线程

用户线程 user thread: 默认是用户线程,系统的工作线程,完成程序的业务操作。不同线程生命周期不同,一般不会同时消失。

守护线程 damon thread: 服务线程,如gc线程。全部用户线程消亡,则守护线程消亡。

3. 线程的生命周期

Java线程状态_价值成长的博客-CSDN博客

①. 新建:就是刚使用new方法,new出来的线程

②. 就绪:就是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段,谁先抢的CPU资源,谁开始执行

③. 运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run方法定义了线程的操作和功能

④. 阻塞:在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态
比如sleep()、wait()之后线程就处于了阻塞状态,这个时候需要其他机制将处于阻塞状态的线程唤醒,比如调用notify或者notifyAll()方法。唤醒的线程不会立刻执行run方法,它们要再次等待CPU分配资源进入运行状态

⑤. 销毁:如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源

在这里插入图片描述

在这里插入图片描述

 在这里插入图片描述

4. 多线程编程步骤

5. Fork/Join框架

并行执行框架,分治思想:

1. 分割任务

2. 执行任务

3. 合并任务

Fork/Join框架主要包含三个模块:

  • 任务对象: ForkJoinTask (包括RecursiveTaskRecursiveActionCountedCompleter)
  • 执行Fork/Join任务的线程: ForkJoinWorkerThread
  • 线程池: ForkJoinPool

这三者的关系是: ForkJoinPool可以通过池中的ForkJoinWorkerThread来处理ForkJoinTask任务。

工作窃取算法:

干完活的线程与其等着,不如去帮其他线程干活,于是它就去其他线程的队列里窃取一个任务来执行。而在这时它们会访问同一个队列,所以为了减少窃取任务线程和被窃取任务线程之间的竞争,通常会使用双端队列,被窃取任务线程永远从双端队列的头部拿任务执行,而窃取任务的线程永远从双端队列的尾部拿任务执行。
 

整个Fork/Join 框架的执行流程/运行机制是怎么样的?

  • 首先介绍任务的提交流程 - 外部任务(external/submissions task)提交
  • 然后介绍任务的提交流程 - 子任务(Worker task)提交
  • 再分析任务的执行过程(ForkJoinWorkerThread.run()到ForkJoinTask.doExec()这一部分);
  • 最后介绍任务的结果获取(ForkJoinTask.join()和ForkJoinTask.invoke())

ForkJoinPool类继承关系:

内部类介绍:

  • ForkJoinWorkerThreadFactory: 内部线程工厂接口,用于创建工作线程ForkJoinWorkerThread

  • DefaultForkJoinWorkerThreadFactory: ForkJoinWorkerThreadFactory 的默认实现类

  • InnocuousForkJoinWorkerThreadFactory: 实现了 ForkJoinWorkerThreadFactory,无许可线程工厂,当系统变量中有系统安全管理相关属性时,默认使用这个工厂创建工作线程。

  • EmptyTask: 内部占位类,用于替换队列中 join 的任务。

  • ManagedBlocker: 为 ForkJoinPool 中的任务提供扩展管理并行数的接口,一般用在可能会阻塞的任务(如在 Phaser 中用于等待 phase 到下一个generation)。

  • WorkQueue: ForkJoinPool 的核心数据结构,本质上是work-stealing 模式的双端任务队列,内部存放 ForkJoinTask 对象任务,使用 @Contented 注解修饰防止伪共享。

    • 工作线程在运行中产生新的任务(通常是因为调用了 fork())时,此时可以把 WorkQueue 的数据结构视为一个栈,新的任务会放入栈顶(top 位);工作线程在处理自己工作队列的任务时,按照 LIFO 的顺序。
    • 工作线程在处理自己的工作队列同时,会尝试窃取一个任务(可能是来自于刚刚提交到 pool 的任务,或是来自于其他工作线程的队列任务),此时可以把 WorkQueue 的数据结构视为一个 FIFO 的队列,窃取的任务位于其他线程的工作队列的队首(base位)。
  • 伪共享状态: 缓存系统中是以缓存行(cache line)为单位存储的。缓存行是2的整数幂个连续字节,一般为32-256个字节。最常见的缓存行大小是64个字节。当多线程修改互相独立的变量时,如果这些变量共享同一个缓存行,就会无意中影响彼此的性能,这就是伪共享。

ForkJoinTask抽象类继承关系:

ForkJoinTask 实现了 Future 接口,说明它也是一个可取消的异步运算任务,实际上ForkJoinTask 是 Future 的轻量级实现,主要用在纯粹是计算的函数式任务或者操作完全独立的对象计算任务。fork 是主运行方法,用于异步执行;而 join 方法在任务结果计算完毕之后才会运行,用来合并或返回计算结果。 其内部类都比较简单,ExceptionNode 是用于存储任务执行期间的异常信息的单向链表;其余四个类是为 Runnable/Callable 任务提供的适配器类,用于把 Runnable/Callable 转化为 ForkJoinTask 类型的任务(因为 ForkJoinPool 只可以运行 ForkJoinTask 类型的任务)。

6.其他

Java多线程实现的四种方式_价值成长的博客-CSDN博客_java多线程有几种实现方法

java线程安全有哪些实现思路?_价值成长的博客-CSDN博客

java并发机制_价值成长的博客-CSDN博客

并发执行的限制_价值成长的博客-CSDN博客

并发编程的两个问题_价值成长的博客-CSDN博客

7. 大局观

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值