JUC(二)JMM(3)
缓存一致性问题及其解决:
问题描述:CPU1缓存与CPU2缓存之间数据不同步的问题。
解决方式:MESI(缓存一致性协议)+ Store Buffer(缓冲区)+ 异步Queue。
Store Buffer:
读写时的更高级缓存。
CPU向缓存写数据:
先写入Store-Buffer。
Invalid则读+设Share。Share则通知别人Invalid+设Exclusive。Exclusive则异步Queue2。Modified则先等变为Exclusive。
CPU从缓存读数据:
先扫描Store-Buffer,如果没找到就去读缓存:
Invalid则读+设Share。Share则直接读。Exclusive则直接读。Modified则先等变为Exclusive。
异步Queue1:
CPU收到Invalid消息 + 把消息写入自身的Invalidate Queue + 异步将目标缓存行设为Invalid(具体时间未知)。
异步Queue2:
CPU向缓存写数据 + 在Modified之后&Exclusive之前 + 异步写入主存(具体什么时候未知)。
缺点:因为 ...
JUC(二)JMM(2) (Volatile + final)
Volatile:保证可见性=变量修改后立即写入储存、保证有序性=禁止指令重排序、但是不保证原子性
Volatile不适用于:20个线程每个线程执行100次对Volatile++,结果肯定小于2000(因为i++是先读再加再赋值&所以需要原子性)
Volatile适用于(指的是不和CAS一起用的场景):作为开关之类的。
Volatile的实现原理:
< 操作Volatile变量 >比< 操作普通变量 >多了一个汇编指令前缀:lock。前缀的意思就是,需要加在普通指令的前面。
(而字节码层面的区别只是多了ACC_VOLATILE的flag而已)
Lock前缀的效果 = mfence全屏障指令的效果。只不过一个是加锁+改+解锁、一个是Invalid+改+保证原子性。
Lock前缀:
对目标变量所在缓存行加锁 (其他CPU对该行的读写操作会被阻塞) +
我CPU强制从主存读 + 工作内存中修改变量 + 强制向主存写 +
释放锁 + 使其他CPU的目标变量所在缓存行Invalid。
全屏障指令 = mfence+地址 ...
JUC(一)JMM(1)
CPU核心态用户态:程序——>轻量级进程——>用户线程线程的调度:协同式调度、抢占式调度。线程六种状态:
左路=Thread.start();中路=时间片的得与失 + yield不释放锁;上路=monitorenter指令时owner不是我+entryList || cxq
左下路waitting= wait()/notify()/notifyAll()释放锁 + join()/等执行完(释放this的锁) + park()/unpark(线程)不会释放锁
右下路Timed_Waiting= sleep(时间)不释放锁 + join(时间) + wait(时间) + parkNanos(时间) + parkUtil(时间)
右路:run方法执行完
如何停止一个正在运行的线程:
本线程在Sleep期间,别人的线程把我t.interrupt()了,则我会抛出异常。
本线程在Sleep之前,本线程就已经t.interrupt()了,则我只要Sleep就会抛出异常。
本线程的逻辑途中写几处检查点Thread.interrupted(),如果外面把我t.interrupt()了则此 ...
Java集合(五)集合遍历
遍历几种方法 :
while (iterator.hasNext()) & iterator.next 、增强for循环、普通for循环、
Foreach + Lambda方法(一个类(外部类或内部类)有自己的iterator + 或者 + 一个类(外部类或内部类)有自己的foreach方法)。
Map的遍历(不可以普通for循环):entrySet、keySet、values
数组遍历(只可以使用增强型for循环、普通for循环):
集合的总结:
真正的无序 = 哈希之后的乱序:遍历时Table[0]Node的next、next + Table[1]Node的next、next
有序集合之比较顺序:
跳表、
PriorityBlockingQueue&DelayedWorkQueue、
TreeMap(并没有选择前中后序遍历(怕层次太多导致栈溢出)而是从最左树的节点(树的最小节点)开始,从小到大拼装树)
有序集合之插入顺序:
有序集合之特殊顺序:
LinkedHashMap & L ...
Java集合(四)Set
HashSet< E > :
元素是HashMap中的key + Value写死是PRESENT = < Object PRESENT = new Object(); >
顺序是啥 = 因为是HashMap所以不是插入顺序、因为是HashMap所以不是自然排序。
LinkedHashSet< E >:
继承于HashSet + 元素是LinkedHashMap中的key + Value写死是PRESENT = < Object PRESENT = new Object(); >
不支持修改LinkedHashMap的accessOrder(只能是fasle)+ 意思是只是插入顺序。
优点:无序去重、logn 、按照插入顺序排序。
应用 =
Spring从配置文件取自动配置类之后的候选集、
低阶广播器SimpleApplicationEventMulticaster维护的广播接收者两个LinkedHashSet。(装广播接收者实例、装beanName)
allkeys-lfu的freqToKeys表HashMap<I ...
Java集合(三)List
ArrayList< E > :
默认长度10、数组elementData、已用长度size(类比map的size)才是真正数据、两个构造(有参构造基于用户传入长度)。
插object = 只尾插 + 不需要移动其他、插index = 只能插到现有size区间的内部或尾巴 + System.arraycopy()只动目标index后。
删object = 找index + System.arraycopy()只动index后、删index = 只能删现有size区间的内部 + System.arraycopy() 只动index后。
不支持查object、只支持查index = 只能查现有size区间的内部 + 返回
扩容 = 1.5倍 + Arrays.copyof()移动老数组
retainAll = 取本集合与入参集合的交集,对本集合读写双指针,结果是写指针本集合。
removeAll = 取本集合与入参集合的差集,对本集合读写双指针,结果是写指针本集合。
ps.
System.arraycopy()方法:传入5个参数(包括新集合),可以复制指定的下标 ...
Java集合(二)Map(2)
WeakHashMap:
与hashmap的计算哈希值不同:不是分成两部分自异或,而是分成四部分自异或。
Entry:Entry<K,V> extends WeakReference< Object >。Entry内部没有维护key字段。取key = 触发父类Reference.get返回referent。
WeakHashMap对标的是ThreadLocalMap。区别是:传入了ReferenceQueue、WeakReference< Object >而不是< ThreadLocal >
弱引用会导致内存泄漏。
ConcurrentSkipListMap:
volatile、cas、没有Synchronized也没有锁
数据节点(右针)Node< KV >:key、value、next属性
索引节点(右针下针)Index< KV >: Node< KV >、right、down属性。 down属性指向的是下方的数据Node的内存地址,所以数据Node的value——&g ...
Java集合(一)Map(1)
HashMap:
TreeNode<K,V>比Node<K,V>多了parent、left、right、prev、color(默认黑色)
缺省长度2^4=16,最大长度2^30即1 << 30 (因为最大只能是2的幂)
树化条件:数组长度达到64 & 某条链表的长度达到8。(如果某链表达到了8,但此时数组没有达到64,则会触发扩容)
反树化条件:某条链表达到长度6 。
默认初始长度16、默认负载因子0.75。自定义长度 -> 初始长度是自定义长度的2次幂。自定义负载因子->使用自定义负载因子。
找桶:key的hashcode自异或+ &length-1
扩容:&length + 分成两部分。扩容后可能需要反树化(因为老树被砍了) + 也可能需要树化(因为把老树乱序了)。
插:找桶+ 链表覆盖 或 链表尾插 或 红黑树覆盖&维护链表顺序 或 红黑树比较位置插入后平衡&维护链表顺序。
节点相等判断条件:《两个node的hash属性(等于key的hashcode自异或)必须相等》 且 《两 ...