线程基础知识
并发问题中锁是用来解决让线程序列化的去访问临界资源,JAVA中有lock和Synchronized两种锁
java 中创建线程的本质只有一种 newThread()
线程的状态有6种
new 刚被创建出来
runnable 就绪状态
blocked 阻塞 (这个是基于monitor锁,syncronized锁,获取资源失败就是阻塞状态)
waiting 等待状态 (这个是我们调用了park,wait,join的时候线程的状态 sleep的底层是通过park实现的)
timed_waiting 线程等待状态 (具有指定等待时间的等待线程的线程状态,超时)
terminated 终止线程的线程状态(线程已完成执行)
如何解决线程安全问题
加锁(synchronized juc包下的lock锁)
所有的并发模式再解决线程安全问题时采用的方案都是序列化的访问临界资源
锁的种类
类别 | synchronized | lock |
---|---|---|
存在层次 | JAVA关键字,再jvm层面优化空间很大 | 是一个类 |
锁的释放 | 以获取锁的线程执行完同步代码块,释放锁,当线程发生异常时JVM会让锁自动时放(底层通过monitor指令实现) | 必须在fainlly代码块中去手动释放锁,不然会造成线程死锁 |
锁的获取 | 假如A线程获取锁,B线程等待,如果A线程阻塞那么B线程会一直等待 | 分情况而定,lock有很多实现,有的可以实现线程去尝试获取锁不需要一直等待 |
锁的状态 | 无法判断 | 可以判断 |
锁的类型 | 可重入,不可中断,非公平锁 | 可重入,可判断,公平非公平都有实现 |
性能 | 少量同步 | 大量同步 |
synchronized实现
JAVAObject中的方法
synchronized实现原理 监视器机制(monitor机制 pthread_mutex_lock/pthread_mutex_unlock)
方法上 :添加ACC_SYNCRONIZED指令实现
代码块:在代码块前后添加monitorenter,和monitorexit,这里会添加两个monitorexit一个正常释放一个异常处理,这也是为什么synchronized不需要手动是释放锁的原因
JVM中的一个monitorObject
锁升级
无锁 —> 偏向锁 —> 轻量级锁 —> 重量级锁
锁降级
所降级发生在GC回收的时候,当判断一个对象中除了当前GC线程持有以外没有其余线程使用,会改回无锁的状态