耐心是一切聪明才智的基础。
java内存模型
java内存模型(java memory model
)是一种规范,是解决多线程在用共享内存时,因为3级缓存,编译器重排,cpu乱序执行,导致的线程安全问题。
3种问题:原子性,可见性,有序性
关键字volatile
保证可见性,有序性
在实现双重检测单例时,就是因为利用了有序性,保证创建对象时按照分配内存->内存中创建对象-> 变量指向内存
的执行顺序。
不能保证原子性,导致一些依赖原值的修改操作,在多线程中会出现问题。
可以用AtomicInteger->longAdder(分段cas并发时性能好)
来实现线程安全。(基于CAS)
写操作前插入写写、写操作后添加写读、读操作前添加读读、读操作后添加读写内存屏障,保证可见性和有序性。
实现线程安全思路
- 锁(
s锁,AQS锁
) - cas(
AtomicInteger
) - 一个线程一套(
ThreadLocal
)
S锁
jdk1.5实现,是个笨锁,操作有用户态内核的上下文切换。
jdk1.6升级了,根据竞争程度一级一级升级。这里也涉及到了自旋锁,因为自旋锁在竞争比较激烈比较费cpu,所以最后转为笨锁,一了百了。

CAS算法
内存值,旧值,新值
。
线程旧值
到新值
运算完之后,回写内存值
时,对比内存值
和旧值
是否相等。
ABA问题可以加版本号处理。
争抢比较多比较费cpu,但是比起s锁没有上下文切换开销。
AQS抽象同步队列
state为0说明没有正在运行的线程,可以直接运行,运行会把state改为1,这时候如果还是这个线程重入加锁,会再进行累加。
双向链表(CHL),有正在运行的线程,又不是自己,r锁默认是非公平锁,会先加到尾插到链表里。
r锁默认是非公平锁,可以创建的时候指定,非公平锁时新加锁的线程会先cas2次去争抢锁,抢到就继续执行,否则park放到链表尾部。公平锁模式,会直接放到park链表尾部。非公平锁具有更高的吞度量,因为新加入线程可能直接执行,没有暂停,放入队列,再唤醒的开销。
Locksupport.park
- 响应中断,但不抛出异常。
- 底层permit布尔值,控制挂起执行。
封装的一些类:
-
ReentrantLock
比起s锁,公平锁,可中断,有状态。
代码块,需要手动释放。-
lock.Condition
实现了s锁的wait nofity
机制。
对应await,signal
方法。
-
-
ReentrantReadWriteLock
读写锁。 -
Semaphore
信号量,控制线程的数量。-
acquire()
数量加一,满了阻塞。 -
release()
数量减一。
-
-
CountDownLatch
倒计时 实现线程同时运行。-
await()
阻塞,等待数减到0。 -
countdown()
数量减一。
-
-
CyclicBarrier
循环屏障(比起countdownLatch可以复用reset)-
await()
阻塞,当所有数量线程都走到此步,继续执行。
-
ThreadLocal
https://www.jianshu.com/p/a20af7b7d113

网友评论