Java并发编程原理 - Unsafe && LockSupport类及AQS同步器的设计

[相关源码]

(https://github.com/Wasabi1234/Java-Concurrency-Progamming-Tutorial)

1 Unsafe类的park和unpark

public native void park(boolean var1, long var2);
public native void unpark(Object var1);
  • park方法用来阻塞一个线程,第一个参数用来指示后面的参数是绝对时间还是相对时间,true表示绝对时间,false表示从此刻开始后的相对时间.调用park的线程就阻塞在此处.
  • unpark用来释放某个线程的阻塞,线程用参数var1表示

举个例子:


2 LockSupport

直接使用Unsafe还是有诸多不便之处,因此lock包提供了一个辅助类LockSupport封装了park和unpark

举个例子:


可以看出,使用LockSupport要比直接只用Unsafe更加便捷。

此外,LockSupport还可以用来给线程设置一个Blocker对象,便于调试和检测线程,其原理是使用Unsafe的putObject方法直接设置Thread对象的parkBlocker属性,并在合适的时候读取这个Blocker对象,例子如下:

3 AQS同步器

各种锁ReentrantLock、ReentrantReadWriteLock以及各种同步器诸Semaphore、CountDownLatch等,核心都是AbstractQueuedSynchronizer

3.1 使用 AQS 手写排它锁

让我们先具体感知它是如何使用的。

这里有一个非常简单的例子SimpleLock,实现了一个最简单的排它锁。

  • 当有线程获得锁时,其他线程只能等待
  • 当这个线程释放锁时,其他线程可以竞争获取锁

运行结果表明,通过简单的几行代码,就实行了一个锁的所有功能。

根据JUC作者的建议,AQS的使用方法要遵循上面这个模式。

使用一个内部类Sync来继承AQS,并实现AQS的相关方法

一般是

  • tryAcquire
  • tryRelease(排它锁)

或者

  • tryAcquireShared
  • tryReleaseShared(共享锁)

在内部使用代理模式实现锁的功能

这样可以让暴露出的同步、互斥方法名由程序员自行决定。
例如各种锁可以使用

  • lock
  • unlock

Semaphore可以使用

  • acquire
  • release

CountDownLatch可以使用

  • await
  • countDown

2 AQS基本原理

要实现一个同步器,需要三个条件:

  1. 一个同步状态值,且可原子操作该状态值.显然CAS胜任
  2. 阻塞线程和解除阻塞线程的机制,可以用LockSupport来实现
  3. 维护一个阻塞线程的队列,并在队列的每个节点中存储线程的状态等信息

让我们看看AQS又是如何设计满足的这三个条件。

2.1 状态值及相应的操作方法

private volatile int state;

protected final int getState() {
    return state;
}

protected final void setState(int newState) {
    state = newState;
}

protected final boolean compareAndSetState(int expect, int update) {
    // See below for intrinsics setup to support this
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

state 为 volatile int型,它的CAS方法,提供原子的比较更新操作。

一般,AQS认为

  • state == 0 时,同步器处于释放状态,多线程此时可竞争获取同步器
  • state ≠ 0 时,同步器处于已获取状态,后续线程需进入队列,等待同步器(可重入同步器允许获取同步器的线程再次进入该同步器,此时使用state计数)
  • 当然,很多情况下,程序员也可自己定义state的值的含义,特别是在实现读写锁时,需要将state一分为二的用。

2.2 阻塞和解除阻塞

LockSupport 提供了阻塞和解除阻塞的功能。因此,所有同步器的阻塞操作其实都是基于LockSupport的,也就是基于Unsafe的park和unpark方法的。

2.3 线程等待队列

AQS内部提供了一个Node类型,它是用来形成“线程等待队列”的节点类型,以及一个由Node类型组成的队列。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,135评论 6 514
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,317评论 3 397
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,596评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,481评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,492评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,153评论 1 309
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,737评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,657评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,193评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,276评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,420评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,093评论 5 349
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,783评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,262评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,390评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,787评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,427评论 2 359

推荐阅读更多精彩内容

  • 云在不停的在变幻着它的姿态 时而像泼墨 时而出现一团光亮 雷在远方怒吼着 偶尔还有闪电 树上的叶子在风中 纷纷扬扬...
    春雨姐阅读 129评论 0 1
  • 碧水悠悠柳色新,也傍钓客在湖滨; 悬钩半日无鱼影,只闻鸣蝉乱我神。
    清净菩提阅读 401评论 2 4
  • 宋代:范仲淹 塞下秋来风景异,衡阳雁去无留意。四面边声连角起,千嶂里,长烟落日孤城闭。 浊酒一杯家万里,燕然未勒归...
    青衣秋水阅读 1,450评论 0 1
  • 郭沐悦 林冲在水浒传中的一百零八好汉也算是一朵奇葩了,他同其他人一样武艺高强,但却没有其他好汉的爱憎分明、粗犷...
    眼里的湖阅读 1,455评论 0 4