1.1 不同线程,对同一资源的访问或修改。
1.2 原子性 JVM规范定义了线程对主存的操作指令:read,load,use,assign,store,write
1.3 可见性------------------------------------------------volatile,final,synchronized,
1.4 有序性-------------read-load,从主存加载数据到线程自己的工作内存中,即保留一个副本,assign,修改之后, 变量副本会同步到主存储区(store- write),何时同步不一定,导致最后在内存中的值不是想象中的。
1. CPU高速缓存
2、主内存
每个锁对象都有两个队列,一个是就绪队列,一个是阻塞队列,就绪队列存储了将要获得锁的线程,阻塞队列存储了被阻塞的线程,当一个被线程被唤醒 (notify)后,才会进入到就绪队列,等待cpu的调度
一个线程执行临界区代码过程如下:
1 获得同步锁
2 清空工作内存
3 从主存拷贝变量副本到工作内存
4 对这些变量计算
5 将变量从工作内存写回到主存
6 释放锁
lock.wait -----释放锁,
lock.notify ----通知lock中阻塞队列里面的某个线程,进入就绪队列。
lcok.notifyAll ---通知所有阻塞队列里的线程。
3.volitle
对变量修改回写到内存,相当于 (store- write)
防止指令重排
4.共享对象不可变
5.原子操作,原子类,底层CAS实现,但是会导致缓存一致性流量,bus风暴,性能降低
MESI协议实现,
1.read,load,assign,use,store,write (底层原子操作)
2.lock,unlock.开放api给用户用,字节码为monitorenter,monitorexit (Syncronized 关键字的底层)
其实是对象头,包含一个锁的位置:
http://blog.csdn.net/hsuxu/article/details/9472371
包含,锁的升级,可升不可降
1. ReentrantLock
在同步竞争不激烈时用synchronized,激烈时用ReentrantLock
ReentrantLock提供了lockInterruptibly()方法可以优先考虑响应中断,而不是像synchronized那样不响应interrupt()操作
同一个线程,持有锁,可以重新获取该锁,即重进入,避免了死锁,内部实现有一个计数器和一个标志位,标志占有的线程。
需要手动释放锁
2.synchronized + 内部锁,或叫互斥锁,会阻塞或等待,直到获取锁,无法重进入,产生死锁
+static 类锁
3.公平锁,非公平锁
公平锁是指多个线程在等待同一个锁时,必须按照申请锁的先后顺序来一次获得锁。
4.自旋锁
线程执行一个忙循环(自旋),等待其他线程释放锁。
5.其他
![这里写图片描述](https://img-blog.csdn.net/20160912192430196)
一.CountDownLatch用法
await()
await(long timeout,TimeUnit unit)
countDown();
二.CyclicBarrier用法
await()
await(long timeout,TimeUnit unit)
第一个版本比较常用,用来挂起当前线程,直至所有线程都到达barrier状态再同时执行后续任务;
第二个版本是让这些线程等待至一定的时间,如果还有线程没有到达barrier状态就直接让到达barrier的线程执行后续任务。
三.Semaphore用法
1
2
3
4
public void acquire() throws InterruptedException { } //获取一个许可
public void acquire(int permits) throws InterruptedException { } //获取permits个许可
public void release() { } //释放一个许可
public void release(int permits) { } //释放permits个许可
控制资源能够被多少线程访问,类似于锁。
双亲委派模型的工作流程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类。
c++——-> bootstrap classloader ———->extension classloader —-> application classloader ——–>selfdefined classloader
1. new Object --> eden , if not enough ---> YoungGC(Minor GC)
2. Survivor Mem not enough ---> YoungGC(Major GC : Old Generation)
3. Old Generation Mem not enough ---> Full GC (Old: CMS)
引用分类:强,软,弱,虚
1.引用计数, 存在循环引用
2.可达性分析算法,即判断一个对象能否到达GC-roots,GC-roots:
虚拟机栈(栈帧中的本地变量表)中引用的对象。
方法区中类静态属性引用的对象。
方法区中常量引用的对象。
本地方法栈中JNI(即一般说的Native方法)引用的对象。
垃圾收集算法:
1.标记-清除 ,直接清除当前位置。
2.复制算法 即复制到另一半,然后回收另一半,一块大eden区,两块小survivor区,将eden区中存活的复制到一块空的survivor区,清理eden和第一个survivor
3.标记-整理,然所有存活对象移动到另一端,清除另一端。
4.分代收集
5.hot-spot的实现:
各个收集器。采用不同的垃圾收集算法
5.1 serial 收集器,单线程,新生代收集器,标记-整理
5.2 ParNew,多线程的serial。
5.3 Parallel Scavenge,新生代,复制算法。
5.4 serial-old
5.5 ParalleOld
5.6 CMS,很短暂的停顿。不会stop the world,标记-清除
eden----> survivor--->old---->perm
年龄,大对象,往后放
初始标记(GCroots)
并发标记
最终标记
筛选回收
1 .分代收集:仍然有分代的概念,不需要其他收集器配合,独立管理整个GC堆。
2 .空间整合:从整体看,是基于“标记-整理”算法实现的,从局部(两个Region之间)看是基于“复 制”算法的。在运行期间不会产生内存碎片。
3 .可预测的停顿:G1跟踪各个Region里垃圾堆积值的价值大小,维护一个优先级队列,每次根据允许 的时间,优先回收价值最大的Region。(这也是Garbage First的由来)
http://unixboy.iteye.com/blog/174173
-Xms
-Xmx JVM 最大内存
-Xmn 年轻代大小
-XX:SuvirorRatio=8 eden:survivor = 8:1
-XX:PretenureSizeThreshold 设置大对象阈值,超过,则直接分配到老年代 只对 parnew 和Serail 收集器有效
-XX:MaxPretenuringThreshold 设置晋升old的阈值 即age的max
-XX:+UseParNewGC:
-XX:+UseG1GC
eden --> survivor age:1
minor GC, age ++
if age >= 15 ----> Old Generation
1.Magic Num :0xCAFFEBABE
2.constant_pool :
1. literal
2. reference name
3.LWP和用户线程混合
SunJdk中用LWP(win,linux)
Map系: HashMap,LinkedHashMap,TreeMap, WeakHashMap, EnumMap,ConcurrentHashMap
List系:ArrayList, LinkedList, Vector, Stack
Set系:HashSet, LinkedHashSet, TreeSet