程序员

Java并发编程原理 - Unsafe && LockSuppo

2020-01-05  本文已影响0人  JavaEdge

[相关源码]

(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);

举个例子:


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的相关方法

一般是

或者

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

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

Semaphore可以使用

CountDownLatch可以使用

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认为

2.2 阻塞和解除阻塞

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

2.3 线程等待队列

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

上一篇下一篇

猜你喜欢

热点阅读