概述

在java中和并发相关的自然是锁了,前面的小节中我们看到的java给我们提供的语言级别的同步原语,下面我们会继续看一下java中的并发编程框架: AQS以及由此衍生而来的各种锁和工具类,不过在进入正题之前,我们还是先看一下支撑AQS框架的类,这样分析起来才有根据。

LockSupport

在java中current包基于AQS框架,而AQS框架基于两个类:

  • LockSupport:提供park、unpark操作(是Unsafe的一个代理,最终调用的还是Unsafe的park、unpark操作)
  • Unsafe :提供CAS操作(一般是通过自旋的方式进行操作,这里的cas应该是使用TSL指令来完成的)

在前面线程状态分析的总结中我们看到了locksupport的park操作最终会是的当前线程进去waiting状态,我们知道Object的wait方法也会 使得当前线程进入waiting的状态,那么两者有什么区别呢?

  • 区别1:locksupport不需要当前线程获取到锁,其所做的操作就仅仅是暂停当前线程,而Object是需要在同步代码块中执行
  • 区别2:locksupport操作的对象是线程,而Object的wait方法操作的对象是object(locksupport操作的过程有点像是线程内部包含了一个object,该object不共享,其作用和java的Object是类似的,下面将给出分析)
  • 区别3:locksupport是精准打击(狙击),而Object是针对一片线程进行的打击(散弹),这样Object的notify最终唤醒的线程就不确定了

java 线程源码

从线程源码的视角来看一下locksupport的park、unpark操作分别做了什么或许就比较好理解上文lockspport的park以及object的wait的区别了。

1
2
3
4
5
6
7
8
9
private:
Parker* _parker;
public:
Parker* parker() { return _parker; }

void JavaThread::initialize() {
// Initialize fields
_parker = Parker::Allocate(this) ;
}

如上,在每一个java线程内部都包含了一个Parker对象,该对象内部维护了一个_counter变量,变量初始值为0,当我们调用park方法的时候,会将 该变量置位为1,而当我们调用unpark的时候则将该变量进行复位,我们看到该变量起到的作用就是一个信号量的作用, 不过该信号量无法积累,最大只能为1。 类比Object的wait方法,该变量就好像是在java线程的内部保存了一个object变量,调用park操作的时候,就有点类似于调用该内部类object的wait方法, 只不过park操作的对象是线程私有的。

总结

这里简单的分析了一下AQS所依赖的基本的类的操作,并通过线程源码的方式描述了locksupport的park、unpark在线程层面上的影响,后面如果有时间的 话,再学习一下c++的基本语法,不然在往下分析就分析不动了