java并发原理
单核cpu支持多线程,通过上下文切换来实现
线程创建和上下文切换 多线程不一定比单线程快。
减少上下文切换:无锁(hash分段取模),CAS,使用最少线程,协程
CAS的思想很简单:三个参数,一个当前内存值V、旧的预期值A、即将更新的值B,当且仅当预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做,并返回false。
线程状态:
线程中断:
hotspot\os\linux\vm\os_linux.cpp interrupted
计算机内存模型
处理器如何实现原子操作:
总线锁:总线锁就是使用处理器提供的一个LOCK#信号,当一个处理器在总线上输出此信号时,其他处理器的请求将被阻塞住,那么该处理器可以独占使用共享内存
缓存锁:锁住总线的消耗太大,于是有了缓存锁,在Lock期间处理器缓存的内存区域会被锁定,其他处理其无法更改该块内存中的数据
MESI
modify enclusive share invalid
原子性
可见性
有序性
编译器(JIT)
处理器(cpu)
java 实现原子操作:
锁和循环cas
cas三大问题:ABA,循环时间开销大;只能保证一个变量的原子操作
volatile
汇编 lock:缓存锁和mesi协议 lock指令含义:1使处理器缓存回写到主存 2是其他处理器缓存失效
内存屏障
可见性
防止内存重排序:
内存屏障
写前 storestore store1 ss
写后storeload store sl load
读前 loadload load1 ll load2
读后loadstore hotspot底层添加barrier;
happened-before:
synchronized: 重入 非公平锁
monitorenter/monitorexit
对象头:
hotspot ObjectMonitor 所以任何一个对象都可以成为锁
锁升级膨胀过程
无锁01:
偏向: 大概率 锁不会竞争,而且由同一个线程获得; 对象头中有偏向线程id
轻量级锁00 :
重量级锁10 :
ObjectMonitor定义的
cxq 、
enterList
锁分类
自旋锁 :很短的时间内,避免线程阻塞和唤醒,使用自旋的方式 去获取锁; 获取失败 park 用户态和内核态的切换
wait/notify:
ObjectWaiter;waitset;park 释放锁 阻塞
从waitset取出, unpark 获取锁 唤醒
join:
threadLocal:
Lock:
lock.lock() _cxq_enterList_cas_park
...
lock.unlock()
AQS: FIFO
Node prev next
reentranlock
公平锁
非公平锁
reentranReadWriteLock
LockSupport:
condition:
aqs conditionObject
独占锁 写独占
共享锁 读共享
currentHashMap:
放弃分段锁
使用synchronized
BlockingQueue:
DelayQueue:
原子类
AtomidBoolean
AtomicInteger
...
unsafe
counDownLatch
共享锁
Semaphore
信号量 限流
线程池
ThreadPoolExecutor:
合理创建线程池:
性质:io密集型 2N cpu密集型 n+1
使用有界队列
Executor框架:
newFixedThreadPool 固定数量
newSingleThreadPool 1个
newCachedThreadPool 没有上限 synchQueue 不存数据
newScheduledThreadpool 延时执行
core
max
keepAlive
unit
blockingQueue
handler
executorService.execute(Runnable run)
Future future = executorService.submit(runnable/callable);