JDK1.8源码阅读(5)–ThreadLocal/Enum/Throwable
一.ThreadLocal类
类图:
这个类并没有继承其他的类或接口。
private final int threadLocalHashCode = nextHashCode(); 原始种子,由内置种子计算而来,用来生成均匀的索引
一个线程可以有多个ThreadLocal实例,各实例之内的原始种子值不相同
一个ThreadLocal实例也可被多个线程共享,此时多个线程内看到的原始种子值是相同的
private static AtomicInteger nextHashCode =new AtomicInteger(); 内置种子,由所有ThreadLocal共享,但每次构造一个ThreadLocal实例,其值都会更新,可以理解为每一个ThreadLocal都具有唯一的标识。
private static final int HASH_INCREMENT = 0x61c88647; 哈希魔数 用来生成伪随机数
private static int nextHashCode() 生成下一个哈希值,根据哈希魔数伪随机生成哈希值
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
protected T initialValue() 初始化值,由子类重写
public static ThreadLocal withInitial(Supplier<? extends S> supplier)
返回一个扩展的ThreadLocal,其关联的初值由supplier给出
public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
return new SuppliedThreadLocal<>(supplier);
}
public ThreadLocal() {} 构造函数
static class ThreadLocalMap 定义了储存数据的结构和方法
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
//保存与ThreadLocal关联的那个值
Object value;
//构造Entry函数,将数据存入Entry,相当于hashMap
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
* 初始容量 - 必须是二的幂。
private static final int INITIAL_CAPACITY = 16;
* 该表,必要时调整大小。 table.length必须总是2的幂。
private Entry[] table;
* 表中的条目数。
private int size = 0;
private int threshold; // Default to 0
* 设置调整大小阈值以保持最差2/3的负载系数。
private void setThreshold(int len) {
threshold = len * 2 / 3;
}
//后一个值
private static int nextIndex(int i, int len) {
return ((i + 1 < len) ? i + 1 : 0);
}
//前一个值
private static int prevIndex(int i, int len) {
return ((i - 1 >= 0) ? i - 1 : len - 1);
}
//构造函数,生成table初始容量16
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
//构造函数,参数也是ThreadLocalMap,将原来的Map复制一下
private ThreadLocalMap(ThreadLocalMap parentMap) {
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
setThreshold(len);
table = new Entry[len];
for (int j = 0; j < len; j++) {
Entry e = parentTable[j];
if (e != null) {
@SuppressWarnings("unchecked")
ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
if (key != null) {
Object value = key.childValue(e.value);
Entry c = new Entry(key, value);
int h = key.threadLocalHashCode & (len - 1);
while (table[h] != null)
h = nextIndex(h, len);
table[h] = c;
size++;
}
}
}
}
//根据key值得到Entry,如果在匹配位置拿不到正确的Entry,就到其附近的位置进行寻找
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
//在附近的位置寻找匹配的值,顺便清理垃圾值
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
Entry[] tab = table;
int len = tab.length;
while (e != null) {
ThreadLocal<?> k = e.get();
if (k == key)
return e;
if (k == null)
expungeStaleEntry(i);
else
i = nextIndex(i, len);
e = tab[i];
}
return null;
}
//设置key和value,
private void set(ThreadLocal<?> key, Object value) {
// We don't use a fast path as with get() because it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not.
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
/**
* Remove the entry for key.
* <p>
* 删除密钥的条目。删除了清理下垃圾值
*
*/
private void remove(ThreadLocal<?> key) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
if (e.get() == key) {
e.clear();
expungeStaleEntry(i);
return;
}
}
}
//将垃圾值赋新值
private void replaceStaleEntry(ThreadLocal<?> key, Object value,
int staleSlot) {
Entry[] tab = table;
int len = tab.length;
Entry e;
int slotToExpunge = staleSlot;
for (int i = prevIndex(staleSlot, len);
(e = tab[i]) != null;
i = prevIndex(i, len))
if (e.get() == null)
slotToExpunge = i;
for (int i = nextIndex(staleSlot, len);
(e = tab[i]) != null;
i = nextIndex(i, len)) {
ThreadLocal<?> k = e.get();
if (k == key) {
e.value = value;
tab[i] = tab[staleSlot];
tab[staleSlot] = e;
// Start expunge at preceding stale entry if it exists
if (slotToExpunge == staleSlot)
slotToExpunge = i;
cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
return;
}
if (k == null && slotToExpunge == staleSlot)
slotToExpunge = i;
}
tab[staleSlot].value = null;
tab[staleSlot] = new Entry(key, value);
if (slotToExpunge != staleSlot)
cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
}
//首先清理位于staleSlot的垃圾值,而后向后遍历(一直遍历到第一个空位置位置),在遍历过程中如果当前位置是个垃圾值就清理,不是垃圾值检测这个值是不是在正确的位置上,如果不在就移动到他应该在的位置(如果应该在的位置有值,就移动到最近的那个位置)
private int expungeStaleEntry(int staleSlot) {
Entry[] tab = table;
int len = tab.length;
// expunge entry at staleSlot
tab[staleSlot].value = null;
tab[staleSlot] = null;
size--;
// Rehash until we encounter null
Entry e;
int i;
for (i = nextIndex(staleSlot, len);
(e = tab[i]) != null;
i = nextIndex(i, len)) {
ThreadLocal<?> k = e.get();
if (k == null) {
e.value = null;
tab[i] = null;
size--;
} else {
int h = k.threadLocalHashCode & (len - 1);
if (h != i) {
tab[i] = null;
// Unlike Knuth 6.4 Algorithm R, we must scan until
// null because multiple entries could have been stale.
while (tab[h] != null)
h = nextIndex(h, len);
tab[h] = e;
}
}
}
return i;
}
//清理槽位,从下标i开始向后遍历,清理一部分垃圾值,清理过后元素依然是紧凑的
private boolean cleanSomeSlots(int i, int n) {
boolean removed = false;
Entry[] tab = table;
int len = tab.length;
do {
i = nextIndex(i, len);
Entry e = tab[i];
if (e != null && e.get() == null) {
n = len;
removed = true;
i = expungeStaleEntry(i);
}
} while ( (n >>>= 1) != 0);
return removed;
}
* 重新包装和/或重新调整桌子的尺寸。首先扫描整个表,删除过时的条目。如果这不足以缩小表的大小,请将表大小加倍。
private void rehash() {
expungeStaleEntries();
// Use lower threshold for doubling to avoid hysteresis
if (size >= threshold - threshold / 4)
resize();
}
/**
* Double the capacity of the table.
* <p>
* 加倍表的容量。
*
*/
private void resize() {
Entry[] oldTab = table;
int oldLen = oldTab.length;
int newLen = oldLen * 2;
Entry[] newTab = new Entry[newLen];
int count = 0;
for (int j = 0; j < oldLen; ++j) {
Entry e = oldTab[j];
if (e != null) {
ThreadLocal<?> k = e.get();
if (k == null) {
e.value = null; // Help the GC
} else {
int h = k.threadLocalHashCode & (newLen - 1);
while (newTab[h] != null)
h = nextIndex(h, newLen);
newTab[h] = e;
count++;
}
}
}
setThreshold(newLen);
size = count;
table = newTab;
}
/**
* Expunge all stale entries in the table.
* <p>
* 清除表中所有失效的条目。
*/
private void expungeStaleEntries() {
Entry[] tab = table;
int len = tab.length;
for (int j = 0; j < len; j++) {
Entry e = tab[j];
if (e != null && e.get() == null)
expungeStaleEntry(j);
}
}
}
public T get()
public T get() {
//首先获取当前线程
Thread t = Thread.currentThread();
//获取Map
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
private T setInitialValue() 初始化map
private T setInitialValue() {
//value是被子类重写的初始化方法生成的值
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
public void set(T value) 设置值
public void remove() 移除值
ThreadLocalMap getMap(Thread t) 返回的是ThreadLocal类中的静态变量,所有线程公用
void createMap(Thread t, T firstValue) 生成新表
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) 复制旧表
T childValue(T parentValue) 获取parentValue,有时会对其进行加工,主要用于测试,参见子类InheritableThreadLocal等。
static final class SuppliedThreadLocal extends ThreadLocal ThreadLocal的一个扩展。其ThreadLocal关联的初值由字段supplier给出
static final class SuppliedThreadLocal<T> extends ThreadLocal<T> {
private final Supplier<? extends T> supplier;
SuppliedThreadLocal(Supplier<? extends T> supplier) {
this.supplier = Objects.requireNonNull(supplier);
}
@Override
protected T initialValue() {
return supplier.get();
}
}
二.Enum类
类图:
枚举类继承了Serializable接口跟Comparable接口
- 示例:
- public enum Color {
-
WHITE, BLACK
- }
- 等价于:
- public final class Color extends Enum {
- public static final Color WHITE = new Color(“WHITE”, 0);
- public static final Color BLACK = new Color(“BLACK”, 1);
- public Color(String name, int ordinal) {
-
super(name, ordinal);
- }
private static final long serialVersionUID = 1L; 序列号
private final String name; 常量名称,不可以修改
public final String name() 得到枚举类的名称
private final int ordinal; 枚举实例的值
public final int ordinal() 返回枚举实例的值
protected Enum(String name, int ordinal) 构造函数,传入名称和值
public String toString() 重写toString方法,返回名称
public final boolean equals(Object other) 判等方法跟==相同
public final int hashCode() 返回Object类的hashCode值
protected final Object clone() 不允许复制
public final int compareTo(E o) 重写Comparable接口,比较ordinal值
public final Class getDeclaringClass() 返回枚举类类对象
public final Class<E> getDeclaringClass() {
Class<?> clazz = getClass();
Class<?> zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
}
protected final void finalize() 枚举类不能有finalize方法
public static <T extends Enum> T valueOf(Class enumType,String name)
public static <T extends Enum<T>> T valueOf(Class<T> enumType,
String name) {
T result = enumType.enumConstantDirectory().get(name);
if (result != null)
return result;
if (name == null)
throw new NullPointerException("Name is null");
throw new IllegalArgumentException(
"No enum constant " + enumType.getCanonicalName() + "." + name);
}
三.Throwable类
异常类,异常体系的祖先
类图:
只继承了Serializable接口
private static final long serialVersionUID = -3042686055658047285L; 序列号
private transient Object backtrace; 本地代码保存了在这个槽中的堆栈回溯的一些指示。
private String detailMessage; 具体细节信息
private static class SentinelHolder Holder类,用于延迟初始化只用于序列化的哨兵对象。
private static class SentinelHolder {
//将堆栈跟踪设置为包含此sentinel值的一个单元数组,表示未来尝试设置堆栈跟踪将被忽略。
public static final StackTraceElement STACK_TRACE_ELEMENT_SENTINEL =
new StackTraceElement("", "", null, Integer.MIN_VALUE);
* 在串行形式中使用的哨兵值,用于指示不可变的堆栈跟踪。
public static final StackTraceElement[] STACK_TRACE_SENTINEL =
new StackTraceElement[] {STACK_TRACE_ELEMENT_SENTINEL};
}
private static final StackTraceElement[] UNASSIGNED_STACK = new StackTraceElement[0]; 初始化一个共享的空栈
插播一个StackTraceElement类:
//正常来讲这个类的初始化是由JVM来完成的,在JDK5之后将这个方法设为public
public final class StackTraceElement implements java.io.Serializable {
// Normally initialized by VM (public constructor added in 1.5)
//私有变量,类名
private String declaringClass;
//方法名称
private String methodName;
//文件夹名称
private String fileName;
//行数
private int lineNumber;
//构造函数
public StackTraceElement(String declaringClass, String methodName,
String fileName, int lineNumber) {
this.declaringClass = Objects.requireNonNull(declaringClass, "Declaring class is null");
this.methodName = Objects.requireNonNull(methodName, "Method name is null");
this.fileName = fileName;
this.lineNumber = lineNumber;
}
public String getFileName() {
return fileName;
}
public int getLineNumber() {
return lineNumber;
}
public String getClassName() {
return declaringClass;
}
public String getMethodName() {
return methodName;
}
//这个栈帧是不是运行在本地方法上的
public boolean isNativeMethod() {
return lineNumber == -2;
}
//重写object的toString方法
public String toString() {
return getClassName() + "." + methodName +
(isNativeMethod() ? "(Native Method)" :
(fileName != null && lineNumber >= 0 ?
"(" + fileName + ":" + lineNumber + ")" :
(fileName != null ? "("+fileName+")" : "(Unknown Source)")));
}
//判等
public boolean equals(Object obj) {
if (obj==this)
return true;
if (!(obj instanceof StackTraceElement))
return false;
StackTraceElement e = (StackTraceElement)obj;
return e.declaringClass.equals(declaringClass) &&
e.lineNumber == lineNumber &&
Objects.equals(methodName, e.methodName) &&
Objects.equals(fileName, e.fileName);
}
/**
* Returns a hash code value for this stack trace element.
*/
public int hashCode() {
int result = 31*declaringClass.hashCode() + methodName.hashCode();
result = 31*result + Objects.hashCode(fileName);
result = 31*result + lineNumber;
return result;
}
private static final long serialVersionUID = 6992337162326171013L;
}
private Throwable cause = this; 将cause赋值为这个实例
private StackTraceElement[] stackTrace = UNASSIGNED_STACK; 将静态变量赋值给实例变量
private static final List SUPPRESSED_SENTINEL =Collections.unmodifiableList(new ArrayList(0));
初始化一个共享的Throwable的集合
private List suppressedExceptions = SUPPRESSED_SENTINEL; 将静态变量赋值给实例的suppressedExceptions
private static final String NULL_CAUSE_MESSAGE = “Cannot suppress a null exception.”; 抑制无错误字段
private static final String SELF_SUPPRESSION_MESSAGE = “Self-suppression not permitted”; 自我抑制字段
private static final String CAUSE_CAPTION = "Caused by: "; 原因标题字段
private static final String SUPPRESSED_CAPTION = "Suppressed: "; 抑制标题字段
public Throwable() 构造函数
public Throwable() {
fillInStackTrace();
}
//加锁的填充堆栈信息
public synchronized Throwable fillInStackTrace() {
//首先判断当前实例的stackTrace是否是空的
if (stackTrace != null ||
backtrace != null /* Out of protocol state */ ) {
fillInStackTrace(0);
stackTrace = UNASSIGNED_STACK;
}
return this;
}
private native Throwable fillInStackTrace(int dummy); //本地方法,填充堆栈信息
public Throwable(String message)
构造函数
public Throwable(String message) {
fillInStackTrace();
detailMessage = message;
}
public Throwable(String message, Throwable cause)
构造函数
public Throwable(String message, Throwable cause) {
fillInStackTrace();
detailMessage = message;
this.cause = cause;
}
public Throwable(Throwable cause)
构造函数
public Throwable(Throwable cause) {
fillInStackTrace();
detailMessage = (cause==null ? null : cause.toString());
this.cause = cause;
}
protected Throwable(String message, Throwable cause,boolean enableSuppression,boolean writableStackTrace)
protected函数
protected Throwable(String message, Throwable cause,
boolean enableSuppression,
boolean writableStackTrace) {
//如果堆栈信息可写就填充堆栈信息,如果不可写就设为null
if (writableStackTrace) {
fillInStackTrace();
} else {
stackTrace = null;
}
detailMessage = message;
this.cause = cause;
if (!enableSuppression)
suppressedExceptions = null;
}
public String getMessage() 返回细节信息
public String getLocalizedMessage()得到本地信息,就是得到细节信息
public synchronized Throwable getCause()
加锁的返回原因,如果原因是这个实例本身就返回null
public synchronized Throwable getCause() {
return (cause==this ? null : cause);
}
public synchronized Throwable initCause(Throwable cause) 初始化原因
public synchronized Throwable initCause(Throwable cause) {
//如果当前实例的原因不等于自身,那么将抛出错误
if (this.cause != this)
throw new IllegalStateException("Can't overwrite cause with " +
Objects.toString(cause, "a null"), this);
//并且参数原因不能等于实例,如果等于将抛出异常
if (cause == this)
throw new IllegalArgumentException("Self-causation not permitted", this);
this.cause = cause;
return this;
}
public String toString()
重写Object的toString方法,如果detailmessage是null就返回类的名称,如果不为空返回detailmessage
public String toString() {
String s = getClass().getName();
String message = getLocalizedMessage();
return (message != null) ? (s + ": " + message) : s;
}
public void printStackTrace() 打印堆栈信息
先看三个内部抽象类:
//抽象类
private abstract static class PrintStreamOrWriter {
/** Returns the object to be locked when using this StreamOrWriter */
//抽象方法lock
abstract Object lock();
/** Prints the specified string as a line on this StreamOrWriter */
//抽象方法打印
abstract void println(Object o);
}
//包装的打印流,操作字节流
private static class WrappedPrintStream extends PrintStreamOrWriter {
private final PrintStream printStream;
//构造函数
WrappedPrintStream(PrintStream printStream) {
this.printStream = printStream;
}
//重写了lock方法,返回常量打印流
Object lock() {
return printStream;
}
//将对象打印出来
void println(Object o) {
printStream.println(o);
}
}
//包装过的打印写,操作字符流
private static class WrappedPrintWriter extends PrintStreamOrWriter {
private final PrintWriter printWriter;
WrappedPrintWriter(PrintWriter printWriter) {
this.printWriter = printWriter;
}
Object lock() {
return printWriter;
}
void println(Object o) {
printWriter.println(o);
}
}
public void printStackTrace() {
printStackTrace(System.err);
}
public void printStackTrace(PrintStream s) {
printStackTrace(new WrappedPrintStream(s));
}
private void printStackTrace(PrintStreamOrWriter s) {
//创建一个泛型为Throwable的set,使用这样的构造方法,我觉得是用工厂模式希望继承IdentityHashMap的判等特性,就是这个新生成的set中判等不是仅仅值相同就可以,还需要引用相同。
Set<Throwable> dejaVu =
Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>());
//将当前实例对象加入到set中
dejaVu.add(this);
//将s.lock上锁(就是printStream)
synchronized (s.lock()) {
// 打印这个对象的toString信息
s.println(this);
//获取堆栈信息
StackTraceElement[] trace = getOurStackTrace();
//打印所有的堆栈信息
for (StackTraceElement traceElement : trace)
s.println("\tat " + traceElement);
//打印附加信息
// Print suppressed exceptions, if any
for (Throwable se : getSuppressed())
se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);
//打印原因
// Print cause, if any
Throwable ourCause = getCause();
if (ourCause != null)
ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
}
}
private void printEnclosedStackTrace(PrintStreamOrWriter s,StackTraceElement[] enclosingTrace,String caption,String prefix,Set dejaVu)打印附加信息
private void printEnclosedStackTrace(PrintStreamOrWriter s,
StackTraceElement[] enclosingTrace,
String caption,
String prefix,
Set<Throwable> dejaVu) {
//断言当前的线程持有printStream的锁
assert Thread.holdsLock(s.lock());
//如果set中包含了当前throwable对象
if (dejaVu.contains(this)) {
s.println("\t[CIRCULAR REFERENCE:" + this + "]");
} else {
dejaVu.add(this);
// Compute number of frames in common between this and enclosing trace
//重新获得trace
StackTraceElement[] trace = getOurStackTrace();
int m = trace.length - 1;
int n = enclosingTrace.length - 1;
while (m >= 0 && n >=0 && trace[m].equals(enclosingTrace[n])) {
m--; n--;
}
//跟不加入当前throwable对象的trace中元素一样的长度
int framesInCommon = trace.length - 1 - m;
// Print our stack trace
s.println(prefix + caption + this);
for (int i = 0; i <= m; i++)
s.println(prefix + "\tat " + trace[i]);
if (framesInCommon != 0)
s.println(prefix + "\t... " + framesInCommon + " more");
// Print suppressed exceptions, if any
for (Throwable se : getSuppressed())
se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION,
prefix +"\t", dejaVu);
// Print cause, if any
Throwable ourCause = getCause();
if (ourCause != null)
ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, prefix, dejaVu);
}
}
public StackTraceElement[] getStackTrace() 返回堆栈信息的复制
public StackTraceElement[] getStackTrace() {
return getOurStackTrace().clone();
}
private synchronized StackTraceElement[] getOurStackTrace() 返回堆栈信息
private synchronized StackTraceElement[] getOurStackTrace() {
// Initialize stack trace field with information from
// backtrace if this is the first call to this method
if (stackTrace == UNASSIGNED_STACK ||
(stackTrace == null && backtrace != null) /* Out of protocol state */) {
//堆栈深度
int depth = getStackTraceDepth();
//初始化stackTrace
stackTrace = new StackTraceElement[depth];
for (int i=0; i < depth; i++)
//获取每个栈帧信息
stackTrace[i] = getStackTraceElement(i);
} else if (stackTrace == null) {
return UNASSIGNED_STACK;
}
return stackTrace;
}
public void setStackTrace(StackTraceElement[] stackTrace) 设置堆栈信息
public void setStackTrace(StackTraceElement[] stackTrace) {
// Validate argument
//备份
StackTraceElement[] defensiveCopy = stackTrace.clone();
for (int i = 0; i < defensiveCopy.length; i++) {
if (defensiveCopy[i] == null)
throw new NullPointerException("stackTrace[" + i + "]");
}
synchronized (this) {
if (this.stackTrace == null && // Immutable stack
backtrace == null) // Test for out of protocol state
return;
this.stackTrace = defensiveCopy;
}
}
native int getStackTraceDepth(); 本地方法,得到栈帧深度
native StackTraceElement getStackTraceElement(int index); 本地方法,找到索引位置的栈帧信息
private void readObject(ObjectInputStream s) 私有方法,
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject(); // read in all fields
if (suppressedExceptions != null) {
List<Throwable> suppressed = null;
if (suppressedExceptions.isEmpty()) {
// Use the sentinel for a zero-length list
suppressed = SUPPRESSED_SENTINEL;
} else { // Copy Throwables to new list
suppressed = new ArrayList<>(1);
for (Throwable t : suppressedExceptions) {
// Enforce constraints on suppressed exceptions in
// case of corrupt or malicious stream.
if (t == null)
throw new NullPointerException(NULL_CAUSE_MESSAGE);
if (t == this)
throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE);
suppressed.add(t);
}
}
suppressedExceptions = suppressed;
}
if (stackTrace != null) {
if (stackTrace.length == 0) {
stackTrace = UNASSIGNED_STACK.clone();
} else if (stackTrace.length == 1 &&
// Check for the marker of an immutable stack trace
SentinelHolder.STACK_TRACE_ELEMENT_SENTINEL.equals(stackTrace[0])) {
stackTrace = null;
} else { // Verify stack trace elements are non-null.
for(StackTraceElement ste : stackTrace) {
if (ste == null)
throw new NullPointerException("null StackTraceElement in serial stream. ");
}
}
} else {
// A null stackTrace field in the serial form can result
// from an exception serialized without that field in
// older JDK releases; treat such exceptions as having
// empty stack traces.
stackTrace = UNASSIGNED_STACK.clone();
}
}
private synchronized void writeObject(ObjectOutputStream s)
private synchronized void writeObject(ObjectOutputStream s)
throws IOException {
// Ensure that the stackTrace field is initialized to a
// non-null value, if appropriate. As of JDK 7, a null stack
// trace field is a valid value indicating the stack trace
// should not be set.
getOurStackTrace();
StackTraceElement[] oldStackTrace = stackTrace;
try {
if (stackTrace == null)
stackTrace = SentinelHolder.STACK_TRACE_SENTINEL;
s.defaultWriteObject();
} finally {
stackTrace = oldStackTrace;
}
}
public final synchronized void addSuppressed(Throwable exception) 添加被抑制的异常
public final synchronized void addSuppressed(Throwable exception) {
//如果要添加的异常是当前对象就抛出异常
if (exception == this)
throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE, exception);
//如果异常是空的抛出异常
if (exception == null)
throw new NullPointerException(NULL_CAUSE_MESSAGE);
if (suppressedExceptions == null) // Suppressed exceptions not recorded
return;
if (suppressedExceptions == SUPPRESSED_SENTINEL)
suppressedExceptions = new ArrayList<>(1);
//将异常加入list
suppressedExceptions.add(exception);
}
private static final Throwable[] EMPTY_THROWABLE_ARRAY = new Throwable[0]; 空的异常类数组
public final synchronized Throwable[] getSuppressed() 得到被抑制的异常
public final synchronized Throwable[] getSuppressed() {
//如果记录抑制异常的list是空的或者就是初始化状态那么就返回空数组
if (suppressedExceptions == SUPPRESSED_SENTINEL ||
suppressedExceptions == null)
return EMPTY_THROWABLE_ARRAY;
else
//否则就把list加到空数组后,返回空数组
return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY);
}