库调多了,都忘了最基础的概念 <锁与线程篇 1>
🍁 作者:知识浅谈,CSDN 博客专家,阿里云签约博主,InfoQ 签约博主,华为云云享专家
📌 擅长领域:全栈工程师、爬虫、ACM 算法
💒 公众号:知识浅谈
XXXX 总结🤞拿下,拿下🤞
温馨提醒:这个有点不忍直视,请捂着眼看下去
🎈线程安全问题是怎么产生的?
由于高并发的环境,导致出现了在单线程下不会出现的问题,使多个线程占用同一个资源,对同一个资源进行修改出现了线程的不安全问题。
内存可见性:在多个线程中,一个线程对变量执行操作后,另一个线程没有及时同步到,因为不同的线程有各自的变量副本,只有通过把自己变量的副本同步到主内存的变量中,被其他线程及时看到才不会出问题。
原子性:多个线程对变量修改的结果要和多个变量按顺序执行的结果一样才能保证原子性,但是如不不进行干预就会出现线程安全问题。
🎈线程安全问题的解决方案有哪些?
一般这个问题的解决方法就是加锁,因为要解决原子性,可见性,多个线程修改冲突等一些线程不安全的问题。使用 synchronized 锁:基于 monitor 的使用 ReentryLock 锁:基于 AQS 的
但是还有其他的方法:使用原子类:AtomicInteger...等使用 ThreadLocal 本地变量。
🎈synchronized 有几种用法?
synchronized 修饰不同的类型:
sychronized 修饰静态方法:锁的使类实例
sychronized 修饰普通方法:锁的使对象实例
修饰代码块 synchronized(Object)
🎈synchronized 底层是如何实现的?
synchronized 锁底层有如下四种:无锁,偏向锁,轻量级锁,重量级锁
偏向锁:把锁状态标记为 01
轻量级锁:00
重量级锁:10 刚开始的时候设置为偏向锁,即所标志状态为 01 当其他线程获取这个锁的时候,如果锁标志位 01,则就升级为轻量级锁,请告诉占用该对象锁的线程,进行 CAS 锁抢占,抢占到该对象锁的获取进行资源的利用,没有获取到的通过 cas 继续获取,在之前的版本中是 CAS 自旋 10 次之后就升级为重量级锁,之后做了优化自适应自旋,判断获取到锁的概率来进行升级,升级到重量级锁,即 monitor 中的 owner 指向当前线程,对象的 markword 记录指向 monitor,线程的 threadrecord 记录 objectmarkword 中内容和执行 object 的指针。
🎈线程休眠的方法有几种?
Thread.sleep(time) 休眠 time 毫秒的时间
object.wait() 休眠,线程进入 waitset,需要被 object.notify(),object.notifyall()唤醒
object.wait(time) 休眠,当经过了 time 时间就自动唤醒
LockSupport.park():休眠当前线程。LockSupport.unpark(Thread thread):唤醒一个指定的线程。
🎈notify 是随机唤醒吗?
notify 不是随即唤醒的,因为 notify 调用的时候还要调用 JVM 的 DequeueWaiter。notify 在源码的注释中说到 notify 选择唤醒的线程是任意的,但是依赖于具体实现的 jvm.而 jvm 中的 DequeueWaiter 确实唤醒 waitset 中的第一个,所以是按顺序唤醒的。
🎈synchronized 和 ReentrantLock 有什么区别?
synchronized 是关键字
synchronized 是基于 monitor 锁的,通过 monitorenter 加锁,monitorexit 解锁 ReentrantLock 是基于 AQS 的,通过 AQS 中的 state 来确定是否是锁获取状态。
两个都是可重入的,ReentrantLock 是基于 state 记录冲入了多少层,synchronized 是基于计数器来确定重入的层数。
synchronized 是非公平锁,ReentrantLock 既支持公平锁也支持非公平锁。
ReentrantLock 加锁解锁需要手动设置,synchronized 是一种隐式的加锁解锁
synchronize 被中断之后会自动解锁,ReentrantLock 被中断之后不会被隐式的解锁,需要手动显式的解锁。
🍚总结
以上是关于线程和锁的总结篇一,希望有所帮助。
版权声明: 本文为 InfoQ 作者【知识浅谈】的原创文章。
原文链接:【http://xie.infoq.cn/article/77b7b3234011de0ab2e1b5213】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论