java.util.concurrent.locks
Lock
实现类:
**ReentrantLock**
:可重入锁(常用)- ReentrantReadWriteLock.
**ReadLock**
:读锁 - ReentrantReadWriteLock.
**WriteLock**
:写锁使用
```java Lock lock = new ReentrantLock(); // 默认非公平锁
// 加锁 lock.lock(); try { // 执行同步代码 } finally { // 解锁 lock.unlock(); }
<a name="Rn4XC"></a>
### 默认锁
ReentrantLock 默认无参构造函数创建的是非公平锁,公平锁可以传递一个值为 true 的布尔值创建。
- 公平锁:非常公平,不能插队,必须先来后到,先来先执行;
- 非公平锁:非常不公平,可以插队(默认是非公平锁);
<a name="B0yHW"></a>
### Lock 与 Synchronized 的区别
<a name="O93Tg"></a>
## Condition
当使用 Lock 替换 synchronized 方法和语句使用时,可以使用 Condition 取代了对象监视器方法使用,使用 Condition.await() 方法和 Condition.signalAll() 方法替代 Object.wait() 和 Object.notifyall()。
<a name="H319s"></a>
### 通知唤醒-与 synchronized 对比
**synchronized**
```java
public synchronized void increment() {
while (number != 0) {
// 等待, 同步方法锁的是当前实例对象
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
number += 1;
System.out.println(Thread.currentThread().getName() + "=>" + number);
this.notifyAll();
}
Lock
final Lock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
public void increment() {
try {
lock.lock();
while (number != 0) {
// 等待, 同步方法锁的是当前实例对象
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
number += 1;
System.out.println(Thread.currentThread().getName() + "=>" + number);
condition.signalAll();
} finally {
lock.unlock();
}
}
精准通知与唤醒
可以创建多个 Condition 对象代表不同情况,signal() 方法精准唤醒。
final Lock lock = new ReentrantLock();
final Condition conditionA = lock.newCondition();
final Condition conditionB = lock.newCondition();
/**
* number = 1 A 执行
* number = 2 B 执行
*/
private int number = 1;
public void printA() {
try {
lock.lock();
while (number != 1) {
// A 等待
conditionA.await();
}
System.out.println(Thread.currentThread().getName() + " -> A");
number = 2;
// 唤醒 B 执行
conditionB.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
ReadWriteLock
实现类
实现类:ReentrantReadWriteLock,可以细粒度的划分为读锁 readLock、写锁 writeLock。其中读锁可以有多个线程同时进行,写锁只允许一个线程进入执行。
方法
Lock readLock()
:读锁Lock writeLock()
:写锁
可以看出,读锁写锁也是属于 Lock 接口的,用法和 Lock 相同。
AbstractQueuedSynchronizer —— AQS
AQS 是一个用来构建锁和同步器的框架,使用AQS能简单且高效地构造出应用广泛的大量的同步器,比如我们提到的 ReentrantLock,Semaphore,其他的诸如 ReentrantReadWriteLock,SynchronousQueue,FutureTask 等等皆是基于 AQS 的。当然,我们自己也能利用 AQS 非常轻松容易地构造出符合我们自己需求的同步器。
AQS 核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制 AQS 是用 CLH 队列锁实现的,即将暂时获取不到锁的线程加入到队列中。
CLH(Craig,Landin,and Hagersten) 队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)。AQS 是将每条请求共享资源的线程封装成一个 CLH 锁队列的一个结点(Node)来实现锁的分配。
java.util.concurrent.atomic
Java 从 JDK1.5 开始提供了 java.util.concurrent.atomic 包(简称 atomic 包),这个包中的原子操作类提供了一种用法简单,性能高效,线程安全地更新一个变量的方式。
用法举例:
- public AtomicInteger():初始化一个默认值为0的原子型Integer
- public AtomicInteger(int initialValue):初始化一个指定值的原子型Integer
- int get():获取值
- int getAndIncrement():以原子方式将当前值加1,注意,这里返回的是自增前的值。
- int incrementAndGet():以原子方式将当前值加1,注意,这里返回的是自增后的值。
- int addAndGet(int data):以原子方式将输入的数值与实例中的值(AtomicInteger里的value)相加,并返回结果。
- int getAndSet(int value):以原子方式设置为newValue的值,并返回旧值。
基本类型
使用原子的方式更新基本类型
- AtomicInteger:整形原子类
- AtomicLong:长整型原子类
-
数组类型
使用原子的方式更新数组里的某个元素
AtomicIntegerArray:整形数组原子类
- AtomicLongArray:长整形数组原子类
AtomicReferenceArray:引用类型数组原子类
引用类型
AtomicReference:引用类型原子类
- AtomicStampedReference:原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于解决原子的更新数据和数据的版本号,可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题。
AtomicMarkableReference :原子更新带有标记位的引用类型
对象的属性修改类型
AtomicIntegerFieldUpdater:原子更新整形字段的更新器
- AtomicLongFieldUpdater:原子更新长整形字段的更新器
- AtomicReferenceFieldUpdater:原子更新引用类型字段的更新器