【Java】の基础——几种线程同步方式

文章目录

  • synchronized关键字
      • 特点
  • ReentrantLock类
      • 特点
      • 原理
      • 阅读源码
  • wait/notifyAll 方式
  • ThreadLocal
  • Semaphore
  • volatile关键字

synchronized关键字

  • 可以修饰方法、对象、成员变量
  • 是可重入锁
  • 可以说是一个几种锁过程的封装:偏向锁、轻量锁、对象锁,自旋锁

特点

  • 不可定时
  • 不可中断

ReentrantLock类

可重入锁。(对于同一个线程,可以继续调用加锁的方法,而不会被挂起)

特点

  • 可以设置超时时间
  • 可以使用多个Condition
  • 可以选择公平锁和非公平锁
  • 可以获得正在等待线程的个数,计数器等

原理

定义state之后,通过cas操作:
自旋 浪费cpu
Yield+自旋 yield让出cpu,但是不能保障下次能否获得锁。
Sleep+自旋 sleep的时间无法确定
park+自旋

ReentrantLock (没有竞争条件下不会用到park,性能好)
pair unpair公平非公平
acquire -> tryAcquare 失败则排队
tryAcquare (公平与非公平区别:公平检查hasQueuedPredecessors,非公平直接cas)
-> hasQueuedPredecessors检查state是否为0,检查是否要排队
如果不需要排队且aqs成功,则设置这个线程为owner线程
Aqs队列:队列的头结点的thread永远为null,队首node的线程是不参与排队。

阅读源码

考虑几种情况

Condition1: aqs=null t1进入
Condition2: aqs=null t1持有锁 t2进入
Condition3: t1持有锁 t2排队 t3进入
Condition4: t2 t3 排队,t1释放锁
Condition5: t1持有锁 t2排队 t3进入时恰好t1释放锁 state=0
Condition6: state=0,aqs只有头。进入t4,最终也是不排队的。
以上 双向链表FIFO队列->CLH自旋锁

知识点文章每篇阅读时间作为复习安排供人参考。

wait/notifyAll 方式

java中每个对象都拥有一个内置锁。

ThreadLocal

将每一个线程存取数据的行为加以隔离,实现的方法就是给予每个线程一个特定空间来保管该线程所独享的资源。
它主要由四个方法组成initialValue(),get(),set(T),remove()。

ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本。

Semaphore

Semaphore信号量被用于控制特定资源在同一个时间被访问的个数。

volatile关键字

保证线程间对统一变量可见性。
禁止指令重排序。
Volatile变量可以确保先行关系,即写操作会发生在后续的读操作之前, 但它并不能保证原子性。

你可能感兴趣的:(Java)