JVM运行时数据区域
JVM栈、native方法栈、程序计数器、堆(字符串常量池)、元空间(运行时常量池,包含类信息、常量、静态变量)
JMM
内存不可见与线程间通信
重排序(编译器、指令、内存)
遵守as-if-serial
原则(数据依赖性)
内存屏障指令
happens-before
关系、规则
如果A线程的写操作a与B线程的读操作b之间存在happens-before关系,尽管a操作和b操作在不同的线程中执行,但JMM向程序员保证a操作将对b操作可见
锁机制
对象头–MarkWord
–线程id+四种锁类型、锁升级的条件
ThreadLocal
同步的措施一般是加锁,这就需要使用者对锁有一定的了解,这显然加重了使用者的负担。
那么有没有一种方式可以做到,当创建一个变量后,每个线程对其进行访问的时候访问的是自己线程的变量呢?其实ThreadLocal就可以做这件事情
在ThreadLocal
的get(),set()
的时候都会清除线程ThreadLocalMap
里所有key为null的value。
而ThreadLocal
的remove()
方法会先将Entry
中对key的弱引用断开,设置为null,然后再清除对应的key为null的value。
remove()方法的关键就在于主动断开entry
的key的引用链接,这样在后续的expungeStaleEntry()
方法中,就会将这种key为null的entry
给设置为null,方便GC对内存进行回收。
CAS
四个数据:对象内存+属性的偏移量+预期值+新值
Unsafe
提供硬件级别的CAS
(javac–javap得到c++代码–发现汇编指令cmpxchg–硬件级别的原子操作)、获取内存中对象的属性的偏移量、操作内存中对象、挂起唤醒线程、获取内存信息、复制内存
程序会根据当前处理器的类型来决定是否为 cmpxchg 指令添加 lock 前缀。如果程序是在多处理器上运行,就为 cmpxchg 指令加上 lock 前缀(lock cmpxchg)。反之,如果程序是在单处理器上运行,就省略 lock 前缀(单处理器自身会维护单处理器内的顺序一致性,不需要 lock 前缀提供的内存屏障效果)。
AtomicInteger
属性:volatile
修饰的value
,unsafe
,valueOffset
Random
属性:AtomicLong
类型的seed
protected int next(int bits) {
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();
nextseed = (oldseed * multiplier + addend) & mask;
} while (!seed.compareAndSet(oldseed, nextseed)); //while循环调用seed的cas方法
return (int)(nextseed >>> (48 - bits));
}
ThreadLocalRandom
public class ThreadLocalRandom extends Random
属性:AtomicInteger
类型的probeGenerator
,AtomicLong
类型的seeder
(new创建时参数传入initialSeed()
)
private static final sun.misc.Unsafe UNSAFE;
private static final long SEED; // Thread#threadLocalRandomSeed的偏移量
private static final long PROBE; // Thread#threadLocalRandomProbe的偏移量
private static final long SECONDARY; // Thread#threadLocalRandomSecondarySeed的偏移量
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> tk = Thread.class;
SEED = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomSeed"));
PROBE = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomProbe"));
SECONDARY = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomSecondarySeed"));
} catch (Exception e) {
throw new Error(e);
}
}
static final void localInit() {
int p = probeGenerator.addAndGet(PROBE_INCREMENT);
int probe = (p == 0) ? 1 : p; // skip 0
long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
Thread t = Thread.currentThread();
UNSAFE.putLong(t, SEED, seed);
UNSAFE.putInt(t, PROBE, probe);
}
final long nextSeed() {
Thread t; long r; // read and update per-thread seed
UNSAFE.putLong(t = Thread.currentThread(), SEED, r = UNSAFE.getLong(t, SEED) + GAMMA);
return r;
}
在ThreadLocalRandom
中并没有存放具体的种子,具体的种子存放在具体的调用线程的threadLocalRandomSeed
变量里面。ThreadLocalRandom
类似于ThreadLocal
类,就是个工具类,注意:它并没有使用ThreadLocal
。
当线程调用ThreadLocalRandom
的current()
方法时,ThreadLocalRandom
负责初始化调用线程的threadLocalRandomSeed
变量,也就是初始化种子。
当调用ThreadLocalRandom
的nextInt()
方法时,实际上是获取当前线程的threadLocalRandomSeed
变量作为当前种子来计算新的种子,然后更新新的种子到当前线程的threadLocalRandomSeed
变量,而后再根据新种子并使用具体算法计算随机数。
其中seeder
和probeGenerator
是两个原子性变量,在初始化调用线程的种子和探针变量时会用到它们,每个线程只会使用一次。
变量instance
是ThreadLocalRandom
的一个实例,该变量是static的。当多线程通过ThreadLocalRandom
的current()
方法获取ThreadLocalRandom
的实例时,其实获取的是同一个实例。
LockSupport
AQS
Node#waitStatus:
- 1:CANCELLED,表示取消排队了
- 0:默认值,表示在正常排队
- -1:SIGNAL,表示释放锁后需要唤醒下一个waitStatus<=0的节点
- -2:CONDITION,表示在条件队列上排队
- -3:PROPAGATE
执行流程:
acquire(int arg)
tryAcquire()
,子类实现,通过CAS改变state值addWaiter()
入队- 尝试直接CAS快速入队(避免大多数情况下的多余判空,见后面的enq)
- 尝试失败,就执行
enq()
,比快速入队多了判断pre=null的操作 - return node
acquireQueue(node, arg)
排队- 若preNode为head,则尝试再次
tryAcquire()
,若成功则设置当前node为head,设置preNode.next=nul(帮助GC),再return。 - 若尝试失败或preNode不是head,则先找到安全点:往前找第一个waitStatus小于等于0的node,设置它的waitStatus为
Signal
,再park挂起自己 - 若能执行到这里,说明被unpark唤醒了,返回
Thread.interrepted()
是为了知道在挂起期间是否被其他线程调用过interrept()
,外层便可判断:若是,就执行Thread.current().interrept()
来响应中断请求!(响应延迟了哦)
- 若preNode为head,则尝试再次
release(int arg)
tryRelease()
,子类实现,通过CAS改变state值- 获取head-Node
- 若head为null或head的waitStatus!=0,则
unparkSuccessor()
- 若head的waitStatus<0(即可能需要信号),则通过CAS置为默认值0(即清除等待信号),因为它使命完成了,成为用来占位的哨兵节点
- 找head的后继节点
- 如果后继节点为null或者后继节点的waitStatus>0,从tail开始往前找(为什么)第一个waitStatus<=0的节点,并unpark它
- 否则,unpark后继节点
- return true
ReentrantLock
非公平锁的tryAcquire()
int c = getState();
//(4)当前AQS状态值为0
if (c == 0) {
// 直接cas获取锁
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
公平锁的tryAcquire()
int c = getState();
//(7)当前AQS状态值为0
if (c == 0) {
//(8)公平性策略
if (! hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
CountDownLatch
ConcurrentHahMap
ThreadPoolExecutor
AtomicInteger
类型的ctl
,高三位表示线程池状态runState
,其余低位表示有效的工作线程数workerCount
内部类Worker
:private final class Worker extends AbstractQueuedSynchronizer implements Runnable
,是一个简单实现的不可重入锁。
并发集合
CopyOnWriteArrayList
并发队列
ConcurrentLinkedQueue
关键属性:
- head: Node
注意: 这里的Node有属性item、next、unsafe、itemOfffset、nextOffset,并提供有方法casItem()和casNext()
- tail: Node
LinkedBlockingQueue
关键属性:
- head: Node
- last: Node
- count: AtomicInteger
- takeLock: ReentrantLock、
- notEmpty: Condition
- putLock: ReentrantLock、
- notFull: Condition