volatile
1轻量级(因为不保证原子性)同步机制
保证可见行
不保证原子性
禁止指令重排序!
2JMM(java内存模型): 规则要求
关于同步的规定
1线程解锁之前,必须吧共享变量的值刷新回驻内存
因为 速度 :硬盘《内存(主内存 硬件8g 16g...)《cpu(缓存 : 各自线程的工作线程)
可见性 : 某个线程修改了值并且写到主内存后 另外一个线程必须马上知道 马上被通知到!
2线程枷锁之前,必须读取主内存的最新值到自己的工作内存
3加锁解锁是同一把锁
三大特性:可见 原子 有序
如何解决原子性:1sync 2使用atomic类
atomic类的cas:
指令冲排序
1单线程环境可以确保结果和顺序执行一样 多线程就不能
2指令重排序必须考虑指令之间的数据依赖性,利用volatile在并发中禁止指令重排序(通过插入内存屏障禁止在内存哦屏障的前后指令进行重排序优化)
volatile
哪些地方用到了:?
1单例模式
DCL双端检锁,某一个线程执行到第一次检测的时候 读取到的变量不为null时 对象可能没有完成初始化 利用volatile禁止指令冲排序
2读写锁
3cas juc包
CAS
比较并交换
底层原理:
1自旋锁:
atomic类底层用的是unsafe类来保证并发无问题 通过unsafe类直接操作内存的数据 在rt sun.misc包中,java cas的操作都依赖unsafe类(根据内存偏移地址获取数据)
cas(cpu的并发原语 原子性)通过unsafe类保证原子性
2对UnSafe的理解:
缺点:
1循环时间厂 吃cpu
2智能保证一个共享变量的原子操作
3ABA问题:某个值可以 A -》 B -》A 是变过的 另外一个线程不知道 以为都是A,操作可以成功但不代表过程没有问题!!!!
则么解决ABA:
每次修改增加修改版本号(类似时间戳)
:atomicStampedReference
atomicReference
自定义的原子类
解决不安全集合类
1Collections。sync 不好 因为加的是syncronized
2copyonwritearraylist /set 写时加锁复制 读写分离思想 可以对容器进行并发的读(读愿容器 写新的复制容器)
concurrenthashmap
公平锁非公平锁 可重入锁
非公平锁(吞吐量大)可重入锁(避免死锁):reentrantlock(默认 ) synchronized
自旋锁
消耗cpu 减少上下文切换 因为不会阻塞
AQS
在这里插入代码片
countDownLatch/CyclicBarrier/Semaphore
netty nio的原理 底层 以及很多高并发的底层也是这三个原理
Semaphore设置资源为1就是lock 和 syncronized
阻塞队列
当阻塞队列是空的时候 从队列中获取元素的操作会阻塞, 阻塞队列是满的时候,往队列里面添加的操作会阻塞
mq消息中间件的底层核心原理!
好处:不需要控制什么时候需要唤醒线程,什么时候需要阻塞线程 blopckingqueue会一手包办 如果自己写的话需要控制效率 线程安全 唤醒 阻塞
红色的阻塞队列就是线程池的底层!!!!
用在哪里:生产者消费者(注意多线程用while不用if) 线程池 消息中间见
synchronized 和 lock 的区别
1原始构成
synchronized是关键字属于jvm层面
底层依靠 monitorenter (monitor对象完成 wait、notify也是依赖monitor对象所以只有在同步块或者代码中才可以调用锁对象的wait notify) 保证正常退出和异常退出,所以不会有死锁,底层一个monitorenter有两个monitorexit
monitorexit
lock是具体类juc的 是api层面的锁
2使用方法
synchronized不需要用户手动释放锁, synchronized代码块执行完毕后系统自动让线程释放锁,synchronized不会有死锁的情况 (1)可重入(2)两个 monitorenter即使异常情况也可以释放锁
lock则需要用户手动释放锁 不释放可能导致死锁
3等待是否可中断
synchronized不可中断 除非抛异常 或者正常运行万
lock 可中断 1 设置超时方法 trylock
2lockInterrupbily()放代码快中 调用interrupt()可以中断
4是否公平
sync非公平锁
reentrlock 都可以 默认非公平
5是否可以精确唤醒线程
sync不可以
reentrlock可以通过condition实现分组唤醒来精确唤醒
线程池
-周期定时循环执行
-1哥线程执行
-缓存 n哥线程无上限
-固定线程数执行
底层都是ThreadpoolExectuor,linked的阻塞队列(cache是sync阻塞队列)
不允许用默认的四个 要么线程数无限大 要么队列无限大 会导致oom
设置的线程池的参数:
初始0
最大:
--cpu密集型的话就设置核数+1
--IO密集型:不是一直在跑CPU 所以可以设置多一点 如CPU核数*2 或者 CPU核数/(1-阻塞系数) 阻塞系数为0.8-0.9
jps -l查线程id
jstack查堆栈线程信息
JVM
-=-=-=-=-=-=-=-=-=–=-=-=-=-=-=-=-=-=–=-=-=-=-=-=-=-=-=–=-=-=-=-=-=-=-=-=–=-=-=-=-=-=-=-=-=–=-=-=-=-=-=-=-=-=–=-=-=-=-=-=-=-=-=–=-=-=-=-=-=-=-=-=
灰色线程私有 只有共有部分方法区、堆会进行垃圾回收!
什么算垃圾:
-引用计数法 : 很可能会有循环引用问题
-枚举GCroot根节点做可达性分析 (复制 标记清楚 标记压缩算法都是这个)
哪些可以作为GCroot:虚拟机栈引用的对象 方法区中类静态属性引用的对象 方法区中常量引用的对象(强引用) 本地方法栈中native方法引用的对象
查看jvm系统默认值:
-Xss 初始栈空间
-Xms -Xmx 初始堆空间和堆的最大值 等价于 -XX:initalHeapSize-XX:MaxHeapSize
-Xmn 年轻代大小
jvm参数类型:标配参数 :-version -help -showversionw
x参数 : -Xint解释执行 -Xcomp编译 -Xmixed混合模式先编译再执行
xx参数(重点)
-Boolean类型: -XX:+ 或者 - 某个属性
kv设置值类型: -XX:MetaspaceSize=128m
jinfo 查看正在运行的java程序的各种信息
jinfo -flag xx参数 线程id : 查看线程是否有开启这个参数 / 某一个属性是多少
-XX:+PrintFlagsInitial 查看jvm初始默认值
-XX:+PrintFlagsFinal 查看修改更新的
-XX:+PrintCommandLIneFLags 查看UseParallelGC参数 查看默认的垃圾回收器
日常项目配置
-=-=-=-=-=-=-=-=-=–=-=-=-=-=-=-=-=-=–=-=-=-=-=-=-=-=-=–=-=-=-=-=-=-=-=-=–=-=-=-=-=-=-=-=-=–=-=-=-=-=-=-=-=-=–=-=-=-=-=-=-=-=-=–=-=-=-=-=-=-=-=-=
GC
参数: -XX:PrintGCDetails
(8 : 1:1)1 : 2
一般GC在Young区 old区才有FUll GC(full gc 的规律 : GC前内存占用空间 -》GC后内存占用 该区域内存总大小 )
引用类型
强引用(90%) 软引用 弱引用 虚引用
强引用 Refereence 经常使用 绝对不会被GC回收的引用 因此强引用是内存泄漏的主要原因
软引用 softReference 当系统内存不足的时候才会被回收 在高速缓存里面会用到(e.g.可以用hashmap存储图片地址 - 图片的对象软引用)
弱引用 weakReference GC垃圾回收一律回收
----weakHashMap 只要key变成null(外界的引用) 就会回收掉这个entry
虚引用 phantomReference 就跟没有任何引用一样(get方法返回null) 任何时候都可以被垃圾回收 不能通过她访问对象 不能单独使用 必须和引用队列ReferenceQUeue联合使用:回收前需要放引用对象到引用队列里 在队列中的引用对象引用的对象被清除之后做对象回收的监控 通知 和其他的行动
OOM
错误:
1stackoverflow 栈溢出
默认大小 512 - 1024 k 递归方法就容易
2 outofmemoryerror :java heap space
异常:
1 outofmemoryerror: GCoverhead limit exceeded
大部分资源都用来GC了 而且效果也不好 清理的内存又很快填满 导致GC一直在运行 就会抛出这异常
2 outofmemoryerror:direct buffer memory