java并发编程

多线程基础

为什么会有多线程
本质原因是摩尔定律失效->多核+分布式时代的来临
硬件发展快CPU 计算能力强

为什么会有多线程

在这里插入图片描述
SMP:对称内存结构

CPU和内存不是直接打交道而是通过BUS数据总线来打交道。

32 和 64位 不是光由CPU决定的 如果BUS是32为CPU64为还是32位 通过总线来交流

NUMA 非一致内存访问CPU架构 即单独的吧CPU和块内存放到一起 CPU需要交互的时候通过Router进行交换。这样做的好处是CPU交换数据较少时,效率比SMP更高,而且NUMA更方便拓展

在这里插入图片描述
线程和进程的区别
基础运行单位是线程 CPU调度的是进程 一个进程中会有一个或者多个线程,进程内的资源相互之间是可以共享的即一个进程中的100个线程可以访问相同的内存。进程和进程之间的资源是隔离的,进程启动再销毁。

当前多数server跑在linux上 linux一切都是文件 所有都是fd CPU也是fd 无论当问硬件,资源linux都有文件路径,文件句柄描述符。再linux所有都是线程 进程映射到内核中,也是内核线程。
在用户线程上,linux一个进程就是一个线程,一个进程多个线程,一个进程fork出一堆子进程,如nginx五个进程都绑定在一个端口上(进程父子关系)等。

java层面
Thread就是一个类,只有调用了start才会跟线程产生关系
JVM层
start后创建JavaThread对象同时去调用操作系统的api,去创建一个操作系统的真实线程,分配jvm的方法栈,堆上的内存缓存区,ready申请cpu时间片启动开始运行run方法体

java多线程*

创建线程的两个方法
new Runnable
new Thread

前台线程 做业务
后台线程 刷新缓存等 守护线程

在这里插入图片描述

Runnable是没有运行能力的只是一个task任务,只有执行了start才开始运行 因为设置了thread.setDaemon为true 所有他是一个守护线程,jvm发现只有一个守护线程,不运行直接停掉。

在这里插入图片描述
Thread实现了Runnable 所有只要重载Thread的run方法是一样的

线程的生命周期
在这里插入图片描述
Thread的重要属性
在这里插入图片描述
线程内部存在计数器会记载run起来的线程中 本条是第几条线程

Runnable的状态为 即将被cpu调起所处的状态
Non-Runnable被阻塞 此时跟cpu没有关系

在这里插入图片描述
wait释放锁+释放cpu
如果只释放cpu那么共同竞争的线程还是不能运行被锁卡住
wait可以通过notify来唤醒
sleep没有唤醒
在这里插入图片描述

1和2是静态方法 影响当前的线程 3是线程实例的方法 4,5是对象的方法不在线程上
一 1.Thread的sleep不释放任何锁2.不在占用cpu
二 2.Thread.yield 从running的状态返回Runnabel的状态

start是一个void返回值的方法,如果想要返回数据使用futureTask<>来进行获取

ThreadA thread = new ThreadA();
FutureTask<String> futureTask = new FutureTask<>(thread)
new Thread(futureTask).start();

Thread.currentThread().getThreadGroup().activeCount();
在这里插入图片描述
线程优先级默认1-10

以下例子synchronized变更了thread1的状态MyThread类中的run被锁住,当到了20次时,join释放了锁,将MyThread跑完再居合到Join的线程跑完。
在这里插入图片描述
在这里插入图片描述
以下例子使用了wait和notifyAll 等待和唤醒 释放锁完成生产者和消费者的例子
在这里插入图片描述
在这里插入图片描述

线程的中断和异常处理

在这里插入图片描述
catch住处理 不然掉裸的原生线程无法处理。

线程状态*
在这里插入图片描述
初始的时候没有真实的线程
经过start之后运行时才有真实的线程
使用yield放弃运行 进入就绪状态

阻塞是被动的 等待是主动的
被动意味着遇到锁 被通知从而在去执行

第一类:
运行和准备runnable ready 准备状态随时等待cpu
第二类
等待 和 超时等待
第三类
阻塞

线程安全*

在这里插入图片描述
如果两个线程对一个全局变量进行+1的操作 分别+1 5000次 最后不等于10000的原因是,当线程A加1的时候如count=99 而这时线程B拿到的也是count=99 那么这两次的+1 实质只加了1次。

并发相关的性质

在这里插入图片描述
A原子性
C一致性
I隔离性
D持久性

在JVM中只有语句1是原子性的
y=x 线程A设定为10 将要赋值的时候 线程B修改为11 将不能保证原子性
如果都是在局部变量将没有关系,局部变量只跟当前单线程有关系

发生线程问题 一定是有竞争关系和共享的资源

在这里插入图片描述
volatile无法保证原子性

可见性是jvm机制导致的,在jvm中,一些变量在多个线程进行共享的时候会被复制出来一个副本。
共享的时候变更后双方都看不到修改后的内容,当加入了volatile关键字之后,强制拿的是主内存的值,强制同步

在这里插入图片描述
8.对象终结规则:一个对象的初始化完成先行完成他的finalize()方法开始。

synchronized 的实现

在这里插入图片描述
synchronized
可以用来锁方法
可以用来锁代码块
可以用来锁对象

同步块:粒度小
同步方法:专有指令
锁的粒度最小对性能影响也最小

volatile

在这里插入图片描述
volatile不能保证原子性 要么加锁 要么使用原子操作类Atomic

volatile会阻止指令重排

final

在这里插入图片描述
在线程里使用线程外的变量一定要是final类型不然会报错

线程池原理与应用*

线程池概述

线程资源是宝贵的
资源宝贵且可以复用 可以用池 可增加代理进行开始结束 不能使线程真的结束,不然要重新创建 ,通过代理向线程池进行借和还的操作
在这里插入图片描述
1 只有执行方法
2 封装启动关闭等的api
3 创建线程池,线程工厂,创建一批线程,批量对线程命名等等
4 实际使用线程池的入口

Executor

在这里插入图片描述
在这里插入图片描述

ExecutorService

在这里插入图片描述
awaitTermination: 等待一段时间

ThreadFactory

在这里插入图片描述
通过线程工厂创建线程:
核心构造:
在这里插入图片描述
核心线程的大小
最大线程的大小
保持存活的时间
时间周期
缓存队列
线程工厂
拒绝策略

1 判断核心线程数,如果不够增加
2 如果核心线程数已经满了,则写进workQueue中
3 如果排队排满了,继续增加线程
4 如果新增满了,采用拒绝策略
IO密集型:大量的请求任务,填满核心线程,使用Q来暂缓,因为核心线程没有处理完,还需要等。
如果Q也满了,那么新建线程来处理堆积在Q里的任务
计算密集型:一次创建更多的线程,反而效率会低

线程池参数

在这里插入图片描述
缓冲队列是为了缓冲任务,把任务都缓存起来,这样在读写两端可以阻塞住,线程空闲来放行 然后继续读,这个模式保证并发安全,让一组多个线程安全的分发任务。
在这里插入图片描述
1是默认的拒绝策略
4 如果线程池已经满了,那么由提交任务的线程直接调用具体任务的代码,此时提交任务的线程将会卡一下因为他正在处理任务从而降低递交速度,线程池的压力就小了。

在这里插入图片描述
2 固定大小的线程数,没有控制队列,队列默认可以一致堆
3 线程数不受限制,如果很忙将会OOM溢出,处理快才不会出现问题。

在这里插入图片描述
最常用的是第二个 固定大小的线程池 他的核心线程数和最大线程数是一样的
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值