并发理论基础:
原子性、有序性、可见性
上下文切换、活跃性问题、死锁问题、线程安全问题
volatile保证有序性、可见性
juc包下类:本质是等待唤醒机制 wait与notify、sleep底层都是 park与unpark 等待唤醒机制 调用操作系统的库函数(linux调用pthread_cond_timedwait)
写出来的程序正确的在cpu上运行、高效(充分的压榨硬件的性能)比如充分的压榨cpu的计算能力以及充分地压榨IO读写的能力、安全怎样去压榨需要了解硬件的工作原理(内存之间如何交互数据、线程之间如何进行通信的、需要了解底层的一些模型)
目标:理解并发的三大特性、jvm工作内存与主内存的关系,知道多线程之间如何通信的,掌握volatile能保证可见性和有序性,掌握cas
管程:monitor synchronized、lock+condition(reentrantlock)
并发编程就是解决线程与线程之间如何同步的(线程之间存在依赖关系、协作 浏览器发送请求到tomcat,tomcat请求数据库)、如何互斥的(共享资源只能我这个线程使用,其他线程得等到我释放这个资源才能使用)、如何分工的(计算一个很大数组的和 10亿,大任务拆分为小的任务,最后再做合并)。解决线程之间的协作问题:解决活跃性问题、死锁问题、线程安全问题(库存超卖);
内存模型:与线程间通信有关 共享内存模型(主内存和工作内存)
这期间可能出现线程安全问题:无锁机制解决方案、有锁机制(synchronized、lock(基于AQS同步器的ReentrantLock、ReentrantReadWritelock与Stampedlock ) )解决方案
并发工具类:atomic包下原子类、线程池(ThreadPoolExecutor、ScheduledThreadPoolExecutor)、线程协作(semaphore用来做限流、Exchanger用来交互数据、CountDownLatch用来模拟并发)、并发容器(将任务丢到队列里面安排一个线程去处理)、future(异步方式)、Fork/join(分工的)、Disruptor(高性能队列)
并发设计模式:
线程对操作系统来说是一种很重的资源,需要切换到内核态去调用系统函数才能创建线程。线程占用内存
并发与并行:并发在宏观上看不出来、在微观上是交替执行的,单核场景下也可以存在。并行是实际存在的物理架构,宏观微观都是可以指令同时运行。目标都是最大化cpu的使用率
Thread.yield() 释放时间片,会发生上下文切换 ,会还原现场 ,会加载上下文,加载到flag=true
volatile:jvm层面 storeload内存屏障 --> (汇编层面指令) lock;addl $0,0(%%rsp) lock前缀指令
立即刷回主内存,缓存失效 lock前缀指令不是内存屏障的指令,但是有内存屏障的效果。保证处理器其他副本失效。缓存失效
有序性的目的是保证可见性
UnsafeFactory.getUnsafe().storeFence();同上
synchronized:调用storefence 内存屏障
LockSupport.unpark(Thread.currentThread) 同上
Thread.sleep(1);内存屏障
Integer:final保证可见性 private final int value; 通过final关键字 保证可见性
总结:java中的可见性是如何保证的方式有两种:1、内存屏障storeload();--》x86 lock替代了mfence;内存屏障可以禁止重排序。2、上下文切换
如何充分压榨硬件资源 压榨cpu计算能力减少cpu等待时间(机械同感)
当前线程对共享变量的操作会存在读不到,或者不能立即读到另一个线程对此变量的写操作
实现:
java
volatile 锁
do while(不可以) 和while(可以)
-Xint(可以)