四,并发编程 - 348052148/learnGraph GitHub Wiki
并发编程
一,并发 和 并行的概念 并发是同时做多件事情,并行是同一时间做多件事情 并发执行可以是串行的,也可以是并行的, 并发属于问题域,并行属于方法域
二,多线程编程痛点 (导火索-线程之间需要同步
- 频繁的上下文切换(性能
- L3缓存失效
- 共享内存时,内存同步问题
- 饥饿-活锁-死锁 (可用性
三,死锁出现的必要条件
- 相互排斥,具有独占权
- 条件等待,进程必须拥有一个资源并且同时等待其他资源
- 不可抢占
- 循环等待。
- 四,并发编程为什么这么难 (不可变解决所有问题
- 竞争条件
- 依赖顺序
- 内存同步
- 原子性
五,java并发编程相关
- Jvm 内存模型,jvm有主内存,负责所有线程共享数据,每个线程有自己的私有内存区,主内存和工作内存分别在jvm的stack 和 heap区
- 线程等待原因,进行io操作阻塞,试图获取锁
- 对原子性的理解要考虑到底层jvm指令
- Volatile变量 来增加内存屏障禁止指令重排,同时直接写入到主内存触发刷新到工作内存,并不能保证原子性,只能保证内存可见性
- sleep和wait区别,wait会解除锁定,sleep只是给出cpu
- 异步编程 + 事件驱动 来替代多线程
六,jvm内存模型
- 主内存 和 工作内存
- 内存交互操作,lock, unlock, read, load, use,assign,store,write
- Volatile 保证可见性,禁止指令重排
- long/double 64位,分2次,不具备原子性
- 原子操作。read、load、assign、use、store、write 可见性。有序性
- 指令重新排序,重排屏障
- 先行发生原则,来保证单线程的顺序性
七,异步编程
- node.js 的异步回调。(其底层实现一个事件处理进程进行事件轮训
八,响应式编程
九, CSP模型 & Actor模型 & Reactor 模型 Reactor 关于同步异步阻塞非阻塞io
十,同步,异步,阻塞,非阻塞 (比较微观的底层
- 同步,请求后等待结果
- 异步,请求后,结果有了进行通知
- 阻塞,调用后等待返回
- 非阻塞,调用后不等待返回
- 异步io和同步io,数据拷贝时,进程是否阻塞,阻塞io和非阻塞io,程序是否阻塞
- 5种io,阻塞io,非阻塞io(依靠轮询,io复用(等待多个io可读(降低阻塞情况),拷贝数据的时候阻塞,信号驱动(拷贝数据阻塞,异步io(完全异步,可读拷贝完成后进行通知
io多路复用是指一个进程可以同时监听多个文件描述符,当其中有一个或多个文件描述符可读或可写的时候,内核会唤醒这个进程
基本元素
{
fd 文件描述符
waitProcessQueue 等待进程队列(阻塞
}
{
process 可执行进程 (进程可重新获取时间片
}
select/poll 模式,每次进行setFds 将进程设置进各个文件描述符的等待队列里。这时进程阻塞。当其中有一个或多个的fds准备好了,内核便将进程从 fd的等待进程队列中移除 加入到执行进程队列中。
fds什么时候准备好呢?
如果是网络socket,网络数据网卡拷贝到内存完毕时,便可以通知准备好了。 流程大概是 网卡接受到数据,出发网卡中断,内核处理中断程序将网卡数据拷贝到内存,然后将等待io的进程加入可执行进程列表,进行再调用系统call,一般是 read,将数据从内核 拷贝到用户内存空间,在这个过程中。阻塞的主要有2部分,等待io数据,拷贝io数据到用户内存空间
//select 每次都必须重新设置一遍讲进程加入fds的操作。因为每次io准备好了都会把进程从fds等待队列中移除。
epoll 模型
{
fds_ready_list
}
epoll 相当于新创建了一个结构,(想起一句在jdon看到的话,没什么是不能加一个抽象层来处理的。如果不行,再抽象一层?)
调用epoll_create时,做了以下事情:
1. 内核帮我们在epoll文件系统里建了个file结点;
2. 在内核cache里建了个红黑树用于存储以后epoll_ctl传来的socket;
3. 建立一个list链表,用于存储准备就绪的事件。
调用epoll_ctl时,做了以下事情:
1. 把socket放到epoll文件系统里file对象对应的红黑树上;
2. 给内核中断处理程序注册一个回调函数,告诉内核,如果这个句柄的中断到了,就把它放到准备就绪list链表里。
调用epoll_wait时,做了以下事情:
观察list链表里有没有数据。有数据就返回,没有数据就sleep,等到timeout时间到后即使链表没数据也返回。而且,通常情况下即使我们要监控百万计的句柄,大多一次也只返回很少量的准备就绪句柄而已,所以,epoll_wait仅需要从内核态copy少量的句柄到用户态而已。
调用epoll_wait时,做了以下事情:
观察list链表里有没有数据。有数据就返回,没有数据就sleep,等到timeout时间到后即使链表没数据也返回。而且,通常情况下即使我们要监控百万计的句柄,大多一次也只返回很少量的准备就绪句柄而已,所以,epoll_wait仅需要从内核态copy少量的句柄到用户态而已。
..所以epoll 依然会存在内核态数据拷贝到用户态阻塞的问题。
十一,select ,epoll 详细 aio
十二,goruntine 绿色线程实现
- 1:1 一个协程对于一个线程
- N:1 n个协程对应一个线程
- N:M M个线程任意调度 goruntine实现
十三,并发模型
悲观锁
- 同步锁
- 自旋锁
- 可重入锁
- 读写锁
乐观锁 和 无锁
- CAS
- Copy On Write
- 原子类
- 线程本地存储(java
- 不变模式