并发概率下的内存模型
java定义了一个内存模型,从硬件/操作系统中抽象出来。对比C/C++直接用操作系统的内存是不同的。
工作内存(working memory):线程自己独占的内存。线程的工作内存是主内存的一份拷贝。
主内存(main memory):实际上存放所有线程的数据的地方。
工作内存和主内存如何交互
这些 都是原子性操作的:
- lock
- unlock
- read
- load
- use
- assign
- store
- write
volatile:直接访问主内存。
一般用于修饰单例,初始化变量。
不能保护变量做运算时候的线程安全。(运算的话使用current包的atoms相关类)
long/double的非原子性协定:
在32位系统中,对long、double进行读写操作, 是分为2个动作的。不过具体JVM会把这个动作原子性实现了。。。
JVM并发特性
- 原子性:
不可切割。lock、unlock。。。等操作;synchronized块。
- 可见性:
一个线程修改了共享变量后,另外一个线程立即看得到。volatile/final/synchronized。
- 有序性:
本线程类观察,所有操作有序;其他线程观察就是无序。(线程内表现为有序)
java线程如何实现
源码中看到, java中的线程都是native本地方法,平台相关性重的。
可能手段:1、使用内核线程;2、使用用户线程;3、使用混合实现(内核线程+用户线程。也就是N:M关系)
线程状态
线程状态:
- new,
- runnable,
- timed waiting,
- waiting,
- blocked,
- terminated.
并发安全
线程安全:多个线程访问一个对象的时候,调用这个对象可以得到正确的结果, 就是线程安全。
锁的作用: 线程a获取到锁可以进入, 其他线程就获取不到锁,进不去。简单点说, 排它操作。
线程安全分级
不可变
final修饰对象。(没有this引用逃逸)
绝对线程安全
一个定义而已, 实际上是木有的。。。
相对线程安全
对象自己线程安全, 但是不保证调用也安全。 绝大部分都是这样子。
例如说并发的修改hashMap里面的某个key的value。
线程兼容
绝大部分都是这样子,比如说hashMap。调用方来保证线程安全
线程对立
例如suspend、resume。这对东西已经过期了。
实现线程安全
1、 互斥同步实现。就是 悲观锁思想。
就是synchronized,或者ReentrantLock。
synchronized 实现就是拆分为 monitorenter, monitorexit.
主要问题是 线程阻塞并且唤醒耗费性能。
2、非阻塞同步。基于 乐观锁思想。
靠CPU实现,基于一些unsafe方法。
例如说atomicInteger等类