并发
什么是并发?
并发是指在同一时间段内,系统中有多个独立的任务同时执行的能力。
为什么要有并发?
提高系统的吞吐量、响应性和资源利用率。
并发能力怎么实现?
并行(计算机硬件必须支持)
多进程的并发(操作系统中同时运行的多个应用程序)
多线程的并发(同一个进程中同时运行的多个任务)(多个线程共享进程的内存空间和上下文环境,上下文切换的代价更小)
并发带来了哪些问题?
1.上下文切换代价过大:
无锁并发编程、CAS算法、避免少任务多线程、协程(单线程多任务)
2.资源的限制程序的执行速度 上传/下载速度、连接数:
增加资源(扩充资源、集群)、限制并发度
3.数据的不一致性 共享数据(程序内部的数据、外部数据)的不一致
4.死锁
正确的使用锁
5.调试难度过大
程序内部的数据一致性
主内存
【线程A 缓存】 【线程B 缓存】
1.比如 主内存中有变量 data1 = 0 , data2 = 0 ,data3 = 0 ,data4 = 0;
2.线程A 执行{ data1 = 1 ; data2 = data3} ;线程B执行 {data3 = 1;data4 = data1};
3.理想状态不发生重排序:data2:data4 可能的结果 0:1 1:0 1:1 实际还会出现在未重排序的情况下出现 0:0
可见性:volatile(易变的) synchronized Lock 确保修改后的数据会立即同步上主内存,其它线程会直接从主内存上读取
原子性: atomic(CAS[乐观锁的模式] + volatile) synchronized Lock
有序性:synchronized(同步:同一时刻只能有一个线程进入代码块) Lock(锁) volatile(禁止指令重排序)
as-if-serial规则(对重排序的一个保证): 编译器和处理器不会对存在数据依赖关系的操作做重排序
happens-before规则(对数据可见性的一个保证):如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前(并不是强制性的,如果重排序后的执行结果与按happens-before规则执行的结果一致,则可能重排序)。
如何建立 happens-before关系:
程序次序:一个线程中的每个操作,happens-before于该线程中的任意后续操作。
监视器锁规则: 解锁 happens-before 加锁
volatite变量修饰: 对一个volatile域的写,happens-before于任意后续对这个volatile域的读
线程start和join: 当一个线程start或join线程时,第一个线程执行的任何操作都“happens-before”第二个线程执行的任何操作。
线程中断: 如果一个线程中断另一个线程,那么第一个线程执行的任何操作都“happens-before”被中断线程执行的任何后续操作。
对象终结规则:一个对象的初始化完成happen-before 于 finalizer() 方法的开始
happen-before的传递性: 如果操作A“happens-before”操作B,并且操作B“happens-before”操作C,则操作A“happens-before”操作C。
控制线程对共享资源的访问(线程之间的同步)
1.synchornized wait notify
2.ReentrantLock Condition
3.ReadWriteLock
4.StampedLock
5.Semaphore
6.CountDownLatch
7.CyclicBarrier
8.Phaser
9.Exchanger
10.FutureTask
11.CompletableFuture
CompletableFuture是Java 8引入的一个新特性,用于实现异步编程和并发操作。
- 异步执行:可以使用CompletableFuture.runAsync()或者CompletableFuture.supplyAsync()方法来创建一个异步任务,并通过thenApply()、thenAccept()等方法对任务进行串行和并行操作。
- 回调机制:可以使用CompletableFuture.thenApply()、thenAccept()等方法来设置回调函数,当异步任务执行完成后,会自动触发回调函数进行后续处理。
- 异常处理:可以使用CompletableFuture.exceptionally()或者handle()方法来处理异步任务执行过程中可能出现的异常情况,并对异常进行捕获和处理。
- 组合操作:可以使用CompletableFuture.thenCompose()或者allOf()等方法将多个异步任务进行组合操作,从而达到更高效的并发处理效果。
- 线程池支持:可以使用CompletableFuture.supplyAsync()方法传递线程池参数,从而控制异步任务的执行所在的线程池,保证线程安全和高效性。
12.ArrayBlockingQueue
1 | ReentrantLock |
java volatile=lock+编译器内存屏障
c/c++ + volatile=