库调多了,都忘了最基础的概念 <锁与线程篇1>

库调多了,都忘了最基础的概念 <锁与线程篇1>

? 作者:知识浅谈,CSDN博客专家,阿里云签约博主,InfoQ签约博主,华为云云享专家

? 擅长领域:全栈工程师、爬虫、ACM算法

? 公众号:知识浅谈

XXXX总结 ?拿下,拿下?

​温馨提醒:这个有点不忍直视,请捂着眼看下去​

?线程安全问题是怎么产生的?

  1. 由于高并发的环境,导致出现了在单线程下不会出现的问题,使多个线程占用同一个资源,对同一个资源进行修改出现了线程的不安全问题。
  2. 内存可见性:在多个线程中,一个线程对变量执行操作后,另一个线程没有及时同步到,因为不同的线程有各自的变量副本,只有通过把自己变量的副本同步到主内存的变量中,被其他线程及时看到才不会出问题。
  3. 原子性:多个线程对变量修改的结果要和多个变量按顺序执行的结果一样才能保证原子性,但是如不不进行干预就会出现线程安全问题。

?线程安全问题的解决方案有哪些?

一般这个问题的解决方法就是加锁,因为要解决原子性,可见性,多个线程修改冲突等一些线程不安全的问题。 使用synchronized锁:基于monitor的 使用ReentryLock锁:基于AQS的

但是还有其他的方法: 使用原子类:AtomicInteger...等 使用ThreadLocal本地变量。

?synchronized有几种用法?

synchronized修饰不同的类型:

  1. sychronized修饰静态方法:锁的使类实例
  2. sychronized修饰普通方法:锁的使对象实例
  3. 修饰代码块synchronized(Object)

?synchronized底层是如何实现的?

synchronized锁底层有如下四种:无锁,偏向锁,轻量级锁,重量级锁

  • 偏向锁:把锁状态标记为01
  • 轻量级锁:00
  • 重量级锁:10 刚开始的时候设置为偏向锁,即所标志状态为01 当其他线程获取这个锁的时候,如果锁标志位01,则就升级为轻量级锁,请告诉占用该对象锁的线程,进行CAS锁抢占,抢占到该对象锁的获取进行资源的利用,没有获取到的通过cas继续获取,在之前的版本中是CAS自旋10次之后就升级为重量级锁,之后做了优化自适应自旋,判断获取到锁的概率来进行升级,升级到重量级锁,即monitor中的owner指向当前线程,对象的markword记录指向monitor,线程的threadrecord记录objectmarkword中内容和执行object的指针。

?线程休眠的方法有几种?

  1. Thread.sleep(time) 休眠time毫秒的时间
  2. object.wait() 休眠,线程进入waitset,需要被object.notify(),object.notifyall()唤醒
  3. object.wait(time) 休眠,当经过了time时间就自动唤醒
  4. LockSupport.park():休眠当前线程。 LockSupport.unpark(Thread thread):唤醒一个指定的线程。

?notify是随机唤醒吗?

notify不是随即唤醒的,因为notify调用的时候还要调用JVM的DequeueWaiter。 notify在源码的注释中说到notify选择唤醒的线程是任意的,但是依赖于具体实现的jvm. 而jvm中的DequeueWaiter确实唤醒waitset中的第一个,所以是按顺序唤醒的。

?synchronized和ReentrantLock有什么区别?

  1. synchronized是关键字
  2. synchronized是基于monitor锁的,通过monitorenter加锁,monitorexit解锁 ReentrantLock是基于AQS的,通过AQS中的state来确定是否是锁获取状态。
  3. 两个都是可重入的,ReentrantLock是基于state记录冲入了多少层,synchronized是基于计数器来确定重入的层数。
  4. synchronized是非公平锁,ReentrantLock既支持公平锁也支持非公平锁。
  5. ReentrantLock加锁解锁需要手动设置,synchronized是一种隐式的加锁解锁
  6. synchronize被中断之后会自动解锁,ReentrantLock被中断之后不会被隐式的解锁,需要手动显式的解锁。

?总结

发表评论

相关文章