java 高并发
本文分为两部分,后半部分是对源码部分解读
ConcurrentHashMap
todo
CompletableFuture
todo
源码
1.Thread
1. java的线程状态
public static enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
private State() {
}
}
2. 中断
java不支持立刻对线程进行stop
操作,suspend
操作deprecated,
interrupt
操作在线程处于 sleep,wait,join
状态时,会抛InterruptedException
,中断标志位会设置为false
//此方法逻辑很明确,宏观效果就是interrupted被设置为false
public void interrupt() {
if (this != currentThread()) {
this.checkAccess();
synchronized(this.blockerLock) {
Interruptible b = this.blocker;
if (b != null) {
this.interrupted = true;
this.interrupt0();
b.interrupt(this);
return;
}
}
}
this.interrupted = true;
this.interrupt0();
}
//判断是否被中断,也就是 interrupted == true,然后设置interrupted == false
public static boolean interrupted() {
Thread t = currentThread();
boolean interrupted = t.interrupted;
// 这里无锁,
if (interrupted) {
t.interrupted = false;
clearInterruptEvent();
}
return interrupted;
}
// 检查是否被中断
public boolean isInterrupted() {
return this.interrupted;
}
- 测试代码
/**
可测试,即使中断后,被中断线程也不会立刻stop
*/
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 500; i++) {
System.out.println(Thread.currentThread().getName() + i);
if (Thread.currentThread().isInterrupted()) {
System.out.println("Interrupted...........");
}
}
}
}, "AqsTest");
t.start();
try {
TimeUnit.MILLISECONDS.sleep(8);
t.interrupt();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
3. 线程阻塞和唤醒机制
- Object
的wait
和notify
,配合synchroized
的对象锁,这两个方法都是native
,会从用户态切换至内核态,这里可能是性能瓶颈
//测试
public static void main(String[] args) {
Object lock = new Object();
// 用这里控制t1和t2的抢占锁顺序,t2先获取锁t1无限等待
AtomicBoolean isThread1First = new AtomicBoolean(false);
Thread t1 = new Thread(new Runnable() {
@SneakyThrows
public void run() {
if (!isThread1First.get()) {
TimeUnit.SECONDS.sleep(1);
}
synchronized (lock) {
System.out.println(Thread.currentThread().getName() +" get lock");
lock.wait();
System.out.println(Thread.currentThread().getName() +" finish");
}
}
}, "thread-1");
Thread t2 = new Thread(new Runnable() {
@SneakyThrows
public void run() {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() +" get lock");
TimeUnit.SECONDS.sleep(1);
lock.notify();
System.out.println(Thread.currentThread().getName() +" finish");
}
}
}, "thread-2");
t1.start();
t2.start();
}
为什么synchronized
和wait
notify
协同使用,主要是和synchronized
的锁优化相关,对象监控
64bit的jvm
的对象头
|-----------------------------------------------------------------------------------------------------------------|
| Object Header(128bits) |
|-----------------------------------------------------------------------------------------------------------------|
| Mark Word(64bits) | Klass Word(64bits) | State |
|-----------------------------------------------------------------------------------------------------------------|
| unused:25|identity_hashcode:31|unused:1|age:4|biase_lock:0| 01 | OOP to metadata object | Nomal |
|-----------------------------------------------------------------------------------------------------------------|
| thread:54| epoch:2 |unused:1|age:4|biase_lock:1| 01 | OOP to metadata object | Biased |
|-----------------------------------------------------------------------------------------------------------------|
| ptr_to_lock_record:62 | 00 | OOP to metadata object | Lightweight Locked |
|-----------------------------------------------------------------------------------------------------------------|
| ptr_to_heavyweight_monitor:62 | 10 | OOP to metadata object | Heavyweight Locked |
|-----------------------------------------------------------------------------------------------------------------|
| | 11 | OOP to metadata object | Marked for GC |
|-----------------------------------------------------------------------------------------------------------------|
- juc
包的Condition
,也就是AQS
的接口,使用上和前者相同
juc的locks包下的Condition接口,具体实现是在 AQS(AbstractQueuedSynchronizer)里的ConditionObject,其中用到了LockSupport
//测试
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Condition con = lock.newCondition();
AtomicBoolean isThread1First = new AtomicBoolean(false);
Thread t1 = new Thread(new Runnable() {
@SneakyThrows
public void run() {
if (!isThread1First.get()) {
TimeUnit.SECONDS.sleep(1);
}
try{
lock.lock();
System.out.println(Thread.currentThread().getName() +" get lock");
con.await();
System.out.println(Thread.currentThread().getName() +" finish");
}finally {
lock.unlock();
}
}
}, "thread-1");
Thread t2 = new Thread(new Runnable() {
@SneakyThrows
public void run() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " get lock");
TimeUnit.SECONDS.sleep(1);
con.signal();
System.out.println(Thread.currentThread().getName() + " finish");
}finally {
lock.unlock();
}
}
}, "thread-2");
t1.start();
t2.start();
System.out.println(System.getProperty("os.name"));
System.out.println(System.getProperty("sun.arch.data.model"));
}
- lockSupport
locksuppot对线程挂起和唤醒顺序无要求
public class LockSupport {
// 这里是 jdk.internal.misc.Unsafe;
// 之前的Unsafe类是这个sun.misc.Unsafe,JDK9以后已经将sun.misc.Unsafe弃用
//同时改进了lib文件的存储方式,将sun.misc.Unsafe全部存储在了jdk.unsupported里面
private static final Unsafe U = Unsafe.getUnsafe();
// ...
public static void park() {
U.park(false, 0L);
}
public static void unpark(Thread thread) {
if (thread != null) {
U.unpark(thread);
}
}
}
// 测试
public static void main(String[] args) {
AtomicBoolean isThread1First = new AtomicBoolean(true);
Thread t1 = new Thread(new Runnable() {
@SneakyThrows
public void run() {
if (!isThread1First.get()) {
TimeUnit.SECONDS.sleep(1);
}
System.out.println(Thread.currentThread().getName() +" get lock");
LockSupport.park();
System.out.println(Thread.currentThread().getName() +" finish");
}
}, "thread-1");
Thread t2 = new Thread(new Runnable() {
@SneakyThrows
public void run() {
System.out.println(Thread.currentThread().getName() + " get lock");
TimeUnit.SECONDS.sleep(1);
LockSupport.unpark(t1);
System.out.println(Thread.currentThread().getName() + " finish");
}
}, "thread-2");
t1.start();
t2.start();
}
4.本类
public class Thread implements Runnable {
// ...
// 线程名
private volatile String name;
//是否守护
private boolean daemon;
// 逻辑
private Runnable target;
//线程组
private ThreadGroup group;
// 状态枚举
public static enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
private State() {
}
}
}
2.AQS
Node
AQS内部的阻塞队列实际是个双向链表,内部抽象静态类Node
,作为基类,其中ConditionNode
就是在LockSupport
中使用到,Node的实现有 ExclusiveNode (独占)
SharedNode(共享)
ConditionNode
abstract static class Node {
volatile Node prev;
volatile Node next;
Thread waiter;
volatile int status;
private static final long STATUS;
private static final long NEXT;
private static final long PREV;
Node() {
}
final boolean casPrev(Node c, Node v) {
return AbstractQueuedSynchronizer.U.weakCompareAndSetReference(this, PREV, c, v);
}
final boolean casNext(Node c, Node v) {
return AbstractQueuedSynchronizer.U.weakCompareAndSetReference(this, NEXT, c, v);
}
final int getAndUnsetStatus(int v) {
return AbstractQueuedSynchronizer.U.getAndBitwiseAndInt(this, STATUS, ~v);
}
final void setPrevRelaxed(Node p) {
AbstractQueuedSynchronizer.U.putReference(this, PREV, p);
}
final void setStatusRelaxed(int s) {
AbstractQueuedSynchronizer.U.putInt(this, STATUS, s);
}
final void clearStatus() {
AbstractQueuedSynchronizer.U.putIntOpaque(this, STATUS, 0);
}
static {
STATUS = AbstractQueuedSynchronizer.U.objectFieldOffset(Node.class, "status");
NEXT = AbstractQueuedSynchronizer.U.objectFieldOffset(Node.class, "next");
PREV = AbstractQueuedSynchronizer.U.objectFieldOffset(Node.class, "prev");
}
}
基类
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements Serializable {
private static final long serialVersionUID = 7373984972572414691L;
static final int WAITING = 1;
static final int CANCELLED = Integer.MIN_VALUE;
static final int COND = 2;
// 懒加载的,如果并发不高,阻塞队列还吃内存没必要
private transient volatile Node head;
private transient volatile Node tail;
// 同步状态
private volatile int state;
private static final Unsafe U = Unsafe.getUnsafe();
private static final long STATE;
private static final long HEAD;
private static final long TAIL;
// ...
// 核心的 CAS 操作
protected final boolean compareAndSetState(int expect, int update) {
return U.compareAndSetInt(this, STATE, expect, update);
}
}
3.ReentrantLock
Lock
首先实现的是 Lock
接口
public interface Lock {
void lock();
// 等待锁时被中断,抛出异常,线程获取锁时调用的
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long var1, TimeUnit var3) throws InterruptedException;
void unlock();
/**
ReentrantLock + Condition await() && signal() 等同于
Synchronized + Object wait() && notifyAll()
*/
Condition newCondition();
}
Sync
ReentrantLock 的内部实现是依赖与Sync
,Sync
又是继承AQS
,Sync的实现有FairSync
和UnFairSync
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
Sync() {
}
// 此注解用于通知jvm编译器为此方法预留固定的栈槽,减少栈帧的分配
@ReservedStackAccess
final boolean tryLock() {
Thread current = Thread.currentThread();
int c = this.getState();
if (c == 0) {
//CAS尝试获取锁
if (this.compareAndSetState(0, 1)) {
//成功设置当前锁Owner线程
this.setExclusiveOwnerThread(current);
return true;
}
// 可重入
} else if (this.getExclusiveOwnerThread() == current) {
++c;
// 这里判断是否溢出,感觉有点草率了,不可能重入这么多次吧
if (c < 0) {
throw new Error("Maximum lock count exceeded");
}
this.setState(c);
return true;
}
return false;
}
// 在 NonFairSync FairSync实现,
abstract boolean initialTryLock();
@ReservedStackAccess
final void lock() {
if (!this.initialTryLock()) {
this.acquire(1);
}
}
/**
尝试释放锁
*/
@ReservedStackAccess
protected final boolean tryRelease(int releases) {
int c = this.getState() - releases;
// 判断加锁和解锁是否是同一线程
if (this.getExclusiveOwnerThread() != Thread.currentThread()) {
throw new IllegalMonitorStateException();
} else {
boolean free = c == 0;
if (free) {
// 设置占有线程 null
this.setExclusiveOwnerThread((Thread)null);
}
//state = 0;后续isLock()有用
this.setState(c);
return free;
}
}
/**
接下来的方法,语义十分明确
*/
protected final boolean isHeldExclusively() {
return this.getExclusiveOwnerThread() == Thread.currentThread();
}
final AbstractQueuedSynchronizer.ConditionObject newCondition() {
return new AbstractQueuedSynchronizer.ConditionObject(this);
}
final Thread getOwner() {
return this.getState() == 0 ? null : this.getExclusiveOwnerThread();
}
final int getHoldCount() {
return this.isHeldExclusively() ? this.getState() : 0;
}
//state == 0 表示未加锁
final boolean isLocked() {
return this.getState() != 0;
}
}
4.CAS
cas是类似与无锁化,是采用操作系统的原语cmpxchg
,cpu执行此指令时,处理器自动锁定总线,禁止其他cpu访问共享变量.执行期间,cpu自动禁止中断,位于java的Unsafe
类中
cas的自旋是对性能的损耗,如何量化cas和锁之间的优劣呢?难道是各有千秋😁?其实从 juc对cas的依赖和其高效的性能,应该是cas要优于锁的
package jdk.internal.misc;
public final class Unsafe {
// 以此类方法compareAndSetXXX作为介绍
//最终的本地方法,用于比较并设置对象的一个字段。如果当前值等于预期值,则将其设置为新的值,并返回 true;否则不做任何更改并返回 false
@IntrinsicCandidate
public final native boolean compareAndSetReference(Object var1, long var2, Object var4, Object var5);
//执行比较和交换操作,并返回旧值
@IntrinsicCandidate
public final native Object compareAndExchangeReference(Object var1, long var2, Object var4, Object var5);
@IntrinsicCandidate
//获取操作上加了一个内存屏障,确保了后续对其他变量的读取不会重排序到这个获取操作之前
public final Object compareAndExchangeReferenceAcquire(Object o, long offset, Object expected, Object x) {
return this.compareAndExchangeReference(o, offset, expected, x);
}
@IntrinsicCandidate
//release 版本,意味着在释放操作上加了一个内存屏障,确保了之前的写操作不会重排序到这个释放操作之后。
public final Object compareAndExchangeReferenceRelease(Object o, long offset, Object expected, Object x) {
return this.compareAndExchangeReference(o, offset, expected, x);
}
@IntrinsicCandidate
//一个弱版本的比较并设置方法,它可能不会总是成功,即便预期值正确。它适合于那些可以容忍偶尔失败的应用场景,比如乐观锁
public final boolean weakCompareAndSetReferencePlain(Object o, long offset, Object expected, Object x) {
return this.compareAndSetReference(o, offset, expected, x);
}
// ....
}