下面是ThreadLocal的测试代码,更多信息请参考注释
- package com.jadyer.thread.local;
- import java.util.Random;
- /**
- * ThreadLocal Test
- * @see =============================================================================================================
- * @see ThreadLocal的作用和目的
- * @see ThreadLocal用于实现线程内的数据共享。即对于相同的代码,多个模块在不同的线程中运行时,分别共享不同的数据
- * @see 每个线程调用全局的ThreadLocal.set()方法,就相当于在其内部的Map中增加一条记录,key是各自的线程,value是各自set()传进去的值
- * @see =============================================================================================================
- * @see ThreadLocal的应用场景
- * @see 例如Struts2中的ActionContext,同一段代码被不同的线程调用运行时,该代码操作的数据是每个线程各自的状态和数据
- * @see 对于不同的线程来说,ActionContext.getContext()方法得到的对象都不相同
- * @see 对于同一个线程来说,ActionContext.getContext()方法无论在哪个模块中或者是被调用多少次,其得到的都是同一个对象
- * @see 通过查看com.opensymphony.xwork2.ActionContex的第43和166行源码,不难发现,Struts2就是这么做的
- * @see =============================================================================================================
- * @see 线程中的成员变量和局部变量
- * @see 成员变量:多个线程操作同一个对象的成员变量时,它们对成员变量的改变是彼此影响的
- * @see 局部变量:每个线程都会有一个该局部变量的拷贝,一个线程对局部变量的改变不会影响到其它线程对该局部变量的操作
- * @see =============================================================================================================
- * @author 宏宇
- * @create Feb 27, 2012 12:10:24 AM
- */
- public class ThreadLocalTest {
- public static void main(String[] args) {
- new Thread(new MyThread(new Random().nextInt())).start();
- new Thread(new MyThread(new Random().nextInt())).start();
- }
- }
- class MyThread implements Runnable{
- private Integer data;
- public MyThread(Integer data){
- this.data = data;
- }
- @Override
- public void run() {
- System.out.println(Thread.currentThread().getName() + " has put data:" + data);
- User.getThreadInstance().setName("name" + data);
- User.getThreadInstance().setAge(data);
- new Pig().getMyData();
- new Dog().getMyData();
- }
- }
- class Pig{
- public void getMyData(){
- User user = User.getThreadInstance();
- System.out.println("Pig from " + Thread.currentThread().getName() + " getMyData:" + user.getName() + "|" + user.getAge());
- }
- }
- class Dog{
- public void getMyData(){
- User user = User.getThreadInstance();
- System.out.println("Dog from " + Thread.currentThread().getName() + " getMyData:" + user.getName() + "|" + user.getAge());
- }
- }
- /**
- * 自定义的线程范围内共享的对象。即该类会针对不同的线程分别创建一个独立的对象
- * @see 此时每个线程得到的将是自己的实例,各线程间得到的实例没有任何关联
- * @see 我们可以拿它,与单例模式中的懒汉式,进行对比,这是个很有意思的东西
- * @see Struts2就是这么设计的,它的每一个请求就是一个线程
- */
- class User{
- private static ThreadLocal<User> instanceMap = new ThreadLocal<User>();
- private User(){}
- /**
- * 得到与当前线程相关的,当前类的实例
- */
- public static /*synchronized*/ User getThreadInstance(){
- User instance = instanceMap.get();
- if(null == instance){
- instance = new User();
- instanceMap.set(instance);
- }
- return instance;
- }
- private String name;
- private int age;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- }
Java ThreadLocal源码
- /*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
- package java.lang;
- import java.lang.ref.*;
- import java.util.concurrent.atomic.AtomicInteger;
- /**
- * This class provides thread-local variables. These variables differ from
- * their normal counterparts in that each thread that accesses one (via its
- * <tt>get</tt> or <tt>set</tt> method) has its own, independently initialized
- * copy of the variable. <tt>ThreadLocal</tt> instances are typically private
- * static fields in classes that wish to associate state with a thread (e.g.,
- * a user ID or Transaction ID).
- *
- * <p>For example, the class below generates unique identifiers local to each
- * thread.
- * A thread's id is assigned the first time it invokes <tt>ThreadId.get()</tt>
- * and remains unchanged on subsequent calls.
- * <pre>
- * import java.util.concurrent.atomic.AtomicInteger;
- *
- * public class ThreadId {
- * // Atomic integer containing the next thread ID to be assigned
- * private static final AtomicInteger nextId = new AtomicInteger(0);
- *
- * // Thread local variable containing each thread's ID
- * private static final ThreadLocal<Integer> threadId =
- * new ThreadLocal<Integer>() {
- * @Override protected Integer initialValue() {
- * return nextId.getAndIncrement();
- * }
- * };
- *
- * // Returns the current thread's unique ID, assigning it if necessary
- * public static int get() {
- * return threadId.get();
- * }
- * }
- * </pre>
- * <p>Each thread holds an implicit reference to its copy of a thread-local
- * variable as long as the thread is alive and the <tt>ThreadLocal</tt>
- * instance is accessible; after a thread goes away, all of its copies of
- * thread-local instances are subject to garbage collection (unless other
- * references to these copies exist).
- *
- * @author Josh Bloch and Doug Lea
- * @since 1.2
- */
- public class ThreadLocal<T> {
- /**
- * ThreadLocals rely on per-thread linear-probe hash maps attached
- * to each thread (Thread.threadLocals and
- * inheritableThreadLocals). The ThreadLocal objects act as keys,
- * searched via threadLocalHashCode. This is a custom hash code
- * (useful only within ThreadLocalMaps) that eliminates collisions
- * in the common case where consecutively constructed ThreadLocals
- * are used by the same threads, while remaining well-behaved in
- * less common cases.
- */
- private final int threadLocalHashCode = nextHashCode();
- /**
- * The next hash code to be given out. Updated atomically. Starts at
- * zero.
- */
- private static AtomicInteger nextHashCode =
- new AtomicInteger();
- /**
- * The difference between successively generated hash codes - turns
- * implicit sequential thread-local IDs into near-optimally spread
- * multiplicative hash values for power-of-two-sized tables.
- */
- private static final int HASH_INCREMENT = 0x61c88647;
- /**
- * Returns the next hash code.
- */
- private static int nextHashCode() {
- return nextHashCode.getAndAdd(HASH_INCREMENT);
- }
- /**
- * Returns the current thread's "initial value" for this
- * thread-local variable. This method will be invoked the first
- * time a thread accesses the variable with the {@link #get}
- * method, unless the thread previously invoked the {@link #set}
- * method, in which case the <tt>initialValue</tt> method will not
- * be invoked for the thread. Normally, this method is invoked at
- * most once per thread, but it may be invoked again in case of
- * subsequent invocations of {@link #remove} followed by {@link #get}.
- *
- * <p>This implementation simply returns <tt>null</tt>; if the
- * programmer desires thread-local variables to have an initial
- * value other than <tt>null</tt>, <tt>ThreadLocal</tt> must be
- * subclassed, and this method overridden. Typically, an
- * anonymous inner class will be used.
- *
- * @return the initial value for this thread-local
- */
- protected T initialValue() {
- return null;
- }
- /**
- * Creates a thread local variable.
- */
- public ThreadLocal() {
- }
- /**
- * Returns the value in the current thread's copy of this
- * thread-local variable. If the variable has no value for the
- * current thread, it is first initialized to the value returned
- * by an invocation of the {@link #initialValue} method.
- *
- * @return the current thread's value of this thread-local
- */
- public T get() {
- Thread t = Thread.currentThread();
- ThreadLocalMap map = getMap(t);
- if (map != null) {
- ThreadLocalMap.Entry e = map.getEntry(this);
- if (e != null)
- return (T)e.value;
- }
- return setInitialValue();
- }
- /**
- * Variant of set() to establish initialValue. Used instead
- * of set() in case user has overridden the set() method.
- *
- * @return the initial value
- */
- private T setInitialValue() {
- T value = initialValue();
- Thread t = Thread.currentThread();
- ThreadLocalMap map = getMap(t);
- if (map != null)
- map.set(this, value);
- else
- createMap(t, value);
- return value;
- }
- /**
- * Sets the current thread's copy of this thread-local variable
- * to the specified value. Most subclasses will have no need to
- * override this method, relying solely on the {@link #initialValue}
- * method to set the values of thread-locals.
- *
- * @param value the value to be stored in the current thread's copy of
- * this thread-local.
- */
- public void set(T value) {
- Thread t = Thread.currentThread();
- ThreadLocalMap map = getMap(t);
- if (map != null)
- map.set(this, value);
- else
- createMap(t, value);
- }
- /**
- * Removes the current thread's value for this thread-local
- * variable. If this thread-local variable is subsequently
- * {@linkplain #get read} by the current thread, its value will be
- * reinitialized by invoking its {@link #initialValue} method,
- * unless its value is {@linkplain #set set} by the current thread
- * in the interim. This may result in multiple invocations of the
- * <tt>initialValue</tt> method in the current thread.
- *
- * @since 1.5
- */
- public void remove() {
- ThreadLocalMap m = getMap(Thread.currentThread());
- if (m != null)
- m.remove(this);
- }
- /**
- * Get the map associated with a ThreadLocal. Overridden in
- * InheritableThreadLocal.
- *
- * @param t the current thread
- * @return the map
- */
- ThreadLocalMap getMap(Thread t) {
- return t.threadLocals;
- }
- /**
- * Create the map associated with a ThreadLocal. Overridden in
- * InheritableThreadLocal.
- *
- * @param t the current thread
- * @param firstValue value for the initial entry of the map
- * @param map the map to store.
- */
- void createMap(Thread t, T firstValue) {
- t.threadLocals = new ThreadLocalMap(this, firstValue);
- }
- /**
- * Factory method to create map of inherited thread locals.
- * Designed to be called only from Thread constructor.
- *
- * @param parentMap the map associated with parent thread
- * @return a map containing the parent's inheritable bindings
- */
- static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
- return new ThreadLocalMap(parentMap);
- }
- /**
- * Method childValue is visibly defined in subclass
- * InheritableThreadLocal, but is internally defined here for the
- * sake of providing createInheritedMap factory method without
- * needing to subclass the map class in InheritableThreadLocal.
- * This technique is preferable to the alternative of embedding
- * instanceof tests in methods.
- */
- T childValue(T parentValue) {
- throw new UnsupportedOperationException();
- }
- /**
- * ThreadLocalMap is a customized hash map suitable only for
- * maintaining thread local values. No operations are exported
- * outside of the ThreadLocal class. The class is package private to
- * allow declaration of fields in class Thread. To help deal with
- * very large and long-lived usages, the hash table entries use
- * WeakReferences for keys. However, since reference queues are not
- * used, stale entries are guaranteed to be removed only when
- * the table starts running out of space.
- */
- static class ThreadLocalMap {
- /**
- * The entries in this hash map extend WeakReference, using
- * its main ref field as the key (which is always a
- * ThreadLocal object). Note that null keys (i.e. entry.get()
- * == null) mean that the key is no longer referenced, so the
- * entry can be expunged from table. Such entries are referred to
- * as "stale entries" in the code that follows.
- */
- static class Entry extends WeakReference<ThreadLocal> {
- /** The value associated with this ThreadLocal. */
- Object value;
- Entry(ThreadLocal k, Object v) {
- super(k);
- value = v;
- }
- }
- /**
- * The initial capacity -- MUST be a power of two.
- */
- private static final int INITIAL_CAPACITY = 16;
- /**
- * The table, resized as necessary.
- * table.length MUST always be a power of two.
- */
- private Entry[] table;
- /**
- * The number of entries in the table.
- */
- private int size = 0;
- /**
- * The next size value at which to resize.
- */
- private int threshold; // Default to 0
- /**
- * Set the resize threshold to maintain at worst a 2/3 load factor.
- */
- private void setThreshold(int len) {
- threshold = len * 2 / 3;
- }
- /**
- * Increment i modulo len.
- */
- private static int nextIndex(int i, int len) {
- return ((i + 1 < len) ? i + 1 : 0);
- }
- /**
- * Decrement i modulo len.
- */
- private static int prevIndex(int i, int len) {
- return ((i - 1 >= 0) ? i - 1 : len - 1);
- }
- /**
- * Construct a new map initially containing (firstKey, firstValue).
- * ThreadLocalMaps are constructed lazily, so we only create
- * one when we have at least one entry to put in it.
- */
- 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);
- }
- /**
- * Construct a new map including all Inheritable ThreadLocals
- * from given parent map. Called only by createInheritedMap.
- *
- * @param parentMap the map associated with parent thread.
- */
- 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) {
- ThreadLocal key = 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++;
- }
- }
- }
- }
- /**
- * Get the entry associated with key. This method
- * itself handles only the fast path: a direct hit of existing
- * key. It otherwise relays to getEntryAfterMiss. This is
- * designed to maximize performance for direct hits, in part
- * by making this method readily inlinable.
- *
- * @param key the thread local object
- * @return the entry associated with key, or null if no such
- */
- 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);
- }
- /**
- * Version of getEntry method for use when key is not found in
- * its direct hash slot.
- *
- * @param key the thread local object
- * @param i the table index for key's hash code
- * @param e the entry at table[i]
- * @return the entry associated with key, or null if no such
- */
- 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;
- }
- /**
- * Set the value associated with key.
- *
- * @param key the thread local object
- * @param value the value to be set
- */
- 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.
- */
- 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;
- }
- }
- }
- /**
- * Replace a stale entry encountered during a set operation
- * with an entry for the specified key. The value passed in
- * the value parameter is stored in the entry, whether or not
- * an entry already exists for the specified key.
- *
- * As a side effect, this method expunges all stale entries in the
- * "run" containing the stale entry. (A run is a sequence of entries
- * between two null slots.)
- *
- * @param key the key
- * @param value the value to be associated with key
- * @param staleSlot index of the first stale entry encountered while
- * searching for key.
- */
- private void replaceStaleEntry(ThreadLocal key, Object value,
- int staleSlot) {
- Entry[] tab = table;
- int len = tab.length;
- Entry e;
- // Back up to check for prior stale entry in current run.
- // We clean out whole runs at a time to avoid continual
- // incremental rehashing due to garbage collector freeing
- // up refs in bunches (i.e., whenever the collector runs).
- int slotToExpunge = staleSlot;
- for (int i = prevIndex(staleSlot, len);
- (e = tab[i]) != null;
- i = prevIndex(i, len))
- if (e.get() == null)
- slotToExpunge = i;
- // Find either the key or trailing null slot of run, whichever
- // occurs first
- for (int i = nextIndex(staleSlot, len);
- (e = tab[i]) != null;
- i = nextIndex(i, len)) {
- ThreadLocal k = e.get();
- // If we find key, then we need to swap it
- // with the stale entry to maintain hash table order.
- // The newly stale slot, or any other stale slot
- // encountered above it, can then be sent to expungeStaleEntry
- // to remove or rehash all of the other entries in run.
- 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 we didn't find stale entry on backward scan, the
- // first stale entry seen while scanning for key is the
- // first still present in the run.
- if (k == null && slotToExpunge == staleSlot)
- slotToExpunge = i;
- }
- // If key not found, put new entry in stale slot
- tab[staleSlot].value = null;
- tab[staleSlot] = new Entry(key, value);
- // If there are any other stale entries in run, expunge them
- if (slotToExpunge != staleSlot)
- cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
- }
- /**
- * Expunge a stale entry by rehashing any possibly colliding entries
- * lying between staleSlot and the next null slot. This also expunges
- * any other stale entries encountered before the trailing null. See
- * Knuth, Section 6.4
- *
- * @param staleSlot index of slot known to have null key
- * @return the index of the next null slot after staleSlot
- * (all between staleSlot and this slot will have been checked
- * for expunging).
- */
- 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;
- }
- /**
- * Heuristically scan some cells looking for stale entries.
- * This is invoked when either a new element is added, or
- * another stale one has been expunged. It performs a
- * logarithmic number of scans, as a balance between no
- * scanning (fast but retains garbage) and a number of scans
- * proportional to number of elements, that would find all
- * garbage but would cause some insertions to take O(n) time.
- *
- * @param i a position known NOT to hold a stale entry. The
- * scan starts at the element after i.
- *
- * @param n scan control: <tt>log2(n)</tt> cells are scanned,
- * unless a stale entry is found, in which case
- * <tt>log2(table.length)-1</tt> additional cells are scanned.
- * When called from insertions, this parameter is the number
- * of elements, but when from replaceStaleEntry, it is the
- * table length. (Note: all this could be changed to be either
- * more or less aggressive by weighting n instead of just
- * using straight log n. But this version is simple, fast, and
- * seems to work well.)
- *
- * @return true if any stale entries have been removed.
- */
- 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;
- }
- /**
- * Re-pack and/or re-size the table. First scan the entire
- * table removing stale entries. If this doesn't sufficiently
- * shrink the size of the table, double the table size.
- */
- private void rehash() {
- expungeStaleEntries();
- // Use lower threshold for doubling to avoid hysteresis
- if (size >= threshold - threshold / 4)
- resize();
- }
- /**
- * Double the capacity of the table.
- */
- 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.
- */
- 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);
- }
- }
- }
- }
Javathread源码
- /*
- * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
- package java.lang;
- import java.lang.ref.Reference;
- import java.lang.ref.ReferenceQueue;
- import java.lang.ref.WeakReference;
- import java.security.AccessController;
- import java.security.AccessControlContext;
- import java.security.PrivilegedAction;
- import java.util.Map;
- import java.util.HashMap;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.ConcurrentMap;
- import java.util.concurrent.locks.LockSupport;
- import sun.nio.ch.Interruptible;
- import sun.security.util.SecurityConstants;
- /**
- * A <i>thread</i> is a thread of execution in a program. The Java
- * Virtual Machine allows an application to have multiple threads of
- * execution running concurrently.
- * <p>
- * Every thread has a priority. Threads with higher priority are
- * executed in preference to threads with lower priority. Each thread
- * may or may not also be marked as a daemon. When code running in
- * some thread creates a new <code>Thread</code> object, the new
- * thread has its priority initially set equal to the priority of the
- * creating thread, and is a daemon thread if and only if the
- * creating thread is a daemon.
- * <p>
- * When a Java Virtual Machine starts up, there is usually a single
- * non-daemon thread (which typically calls the method named
- * <code>main</code> of some designated class). The Java Virtual
- * Machine continues to execute threads until either of the following
- * occurs:
- * <ul>
- * <li>The <code>exit</code> method of class <code>Runtime</code> has been
- * called and the security manager has permitted the exit operation
- * to take place.
- * <li>All threads that are not daemon threads have died, either by
- * returning from the call to the <code>run</code> method or by
- * throwing an exception that propagates beyond the <code>run</code>
- * method.
- * </ul>
- * <p>
- * There are two ways to create a new thread of execution. One is to
- * declare a class to be a subclass of <code>Thread</code>. This
- * subclass should override the <code>run</code> method of class
- * <code>Thread</code>. An instance of the subclass can then be
- * allocated and started. For example, a thread that computes primes
- * larger than a stated value could be written as follows:
- * <p><hr><blockquote><pre>
- * class PrimeThread extends Thread {
- * long minPrime;
- * PrimeThread(long minPrime) {
- * this.minPrime = minPrime;
- * }
- *
- * public void run() {
- * // compute primes larger than minPrime
- * . . .
- * }
- * }
- * </pre></blockquote><hr>
- * <p>
- * The following code would then create a thread and start it running:
- * <p><blockquote><pre>
- * PrimeThread p = new PrimeThread(143);
- * p.start();
- * </pre></blockquote>
- * <p>
- * The other way to create a thread is to declare a class that
- * implements the <code>Runnable</code> interface. That class then
- * implements the <code>run</code> method. An instance of the class can
- * then be allocated, passed as an argument when creating
- * <code>Thread</code>, and started. The same example in this other
- * style looks like the following:
- * <p><hr><blockquote><pre>
- * class PrimeRun implements Runnable {
- * long minPrime;
- * PrimeRun(long minPrime) {
- * this.minPrime = minPrime;
- * }
- *
- * public void run() {
- * // compute primes larger than minPrime
- * . . .
- * }
- * }
- * </pre></blockquote><hr>
- * <p>
- * The following code would then create a thread and start it running:
- * <p><blockquote><pre>
- * PrimeRun p = new PrimeRun(143);
- * new Thread(p).start();
- * </pre></blockquote>
- * <p>
- * Every thread has a name for identification purposes. More than
- * one thread may have the same name. If a name is not specified when
- * a thread is created, a new name is generated for it.
- * <p>
- * Unless otherwise noted, passing a {@code null} argument to a constructor
- * or method in this class will cause a {@link NullPointerException} to be
- * thrown.
- *
- * @author unascribed
- * @see Runnable
- * @see Runtime#exit(int)
- * @see #run()
- * @see #stop()
- * @since JDK1.0
- */
- public
- class Thread implements Runnable {
- /* Make sure registerNatives is the first thing <clinit> does. */
- private static native void registerNatives();
- static {
- registerNatives();
- }
- private char name[];
- private int priority;
- private Thread threadQ;
- private long eetop;
- /* Whether or not to single_step this thread. */
- private boolean single_step;
- /* Whether or not the thread is a daemon thread. */
- private boolean daemon = false;
- /* JVM state */
- private boolean stillborn = false;
- /* What will be run. */
- private Runnable target;
- /* The group of this thread */
- private ThreadGroup group;
- /* The context ClassLoader for this thread */
- private ClassLoader contextClassLoader;
- /* The inherited AccessControlContext of this thread */
- private AccessControlContext inheritedAccessControlContext;
- /* For autonumbering anonymous threads. */
- private static int threadInitNumber;
- private static synchronized int nextThreadNum() {
- return threadInitNumber++;
- }
- /* ThreadLocal values pertaining to this thread. This map is maintained
- * by the ThreadLocal class. */
- ThreadLocal.ThreadLocalMap threadLocals = null;
- /*
- * InheritableThreadLocal values pertaining to this thread. This map is
- * maintained by the InheritableThreadLocal class.
- */
- ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
- /*
- * The requested stack size for this thread, or 0 if the creator did
- * not specify a stack size. It is up to the VM to do whatever it
- * likes with this number; some VMs will ignore it.
- */
- private long stackSize;
- /*
- * JVM-private state that persists after native thread termination.
- */
- private long nativeParkEventPointer;
- /*
- * Thread ID
- */
- private long tid;
- /* For generating thread ID */
- private static long threadSeqNumber;
- /* Java thread status for tools,
- * initialized to indicate thread 'not yet started'
- */
- private volatile int threadStatus = 0;
- private static synchronized long nextThreadID() {
- return ++threadSeqNumber;
- }
- /**
- * The argument supplied to the current call to
- * java.util.concurrent.locks.LockSupport.park.
- * Set by (private) java.util.concurrent.locks.LockSupport.setBlocker
- * Accessed using java.util.concurrent.locks.LockSupport.getBlocker
- */
- volatile Object parkBlocker;
- /* The object in which this thread is blocked in an interruptible I/O
- * operation, if any. The blocker's interrupt method should be invoked
- * after setting this thread's interrupt status.
- */
- private volatile Interruptible blocker;
- private final Object blockerLock = new Object();
- /* Set the blocker field; invoked via sun.misc.SharedSecrets from java.nio code
- */
- void blockedOn(Interruptible b) {
- synchronized (blockerLock) {
- blocker = b;
- }
- }
- /**
- * The minimum priority that a thread can have.
- */
- public final static int MIN_PRIORITY = 1;
- /**
- * The default priority that is assigned to a thread.
- */
- public final static int NORM_PRIORITY = 5;
- /**
- * The maximum priority that a thread can have.
- */
- public final static int MAX_PRIORITY = 10;
- /**
- * Returns a reference to the currently executing thread object.
- *
- * @return the currently executing thread.
- */
- public static native Thread currentThread();
- /**
- * A hint to the scheduler that the current thread is willing to yield
- * its current use of a processor. The scheduler is free to ignore this
- * hint.
- *
- * <p> Yield is a heuristic attempt to improve relative progression
- * between threads that would otherwise over-utilise a CPU. Its use
- * should be combined with detailed profiling and benchmarking to
- * ensure that it actually has the desired effect.
- *
- * <p> It is rarely appropriate to use this method. It may be useful
- * for debugging or testing purposes, where it may help to reproduce
- * bugs due to race conditions. It may also be useful when designing
- * concurrency control constructs such as the ones in the
- * {@link java.util.concurrent.locks} package.
- */
- public static native void yield();
- /**
- * Causes the currently executing thread to sleep (temporarily cease
- * execution) for the specified number of milliseconds, subject to
- * the precision and accuracy of system timers and schedulers. The thread
- * does not lose ownership of any monitors.
- *
- * @param millis
- * the length of time to sleep in milliseconds
- *
- * @throws IllegalArgumentException
- * if the value of {@code millis} is negative
- *
- * @throws InterruptedException
- * if any thread has interrupted the current thread. The
- * <i>interrupted status</i> of the current thread is
- * cleared when this exception is thrown.
- */
- public static native void sleep(long millis) throws InterruptedException;
- /**
- * Causes the currently executing thread to sleep (temporarily cease
- * execution) for the specified number of milliseconds plus the specified
- * number of nanoseconds, subject to the precision and accuracy of system
- * timers and schedulers. The thread does not lose ownership of any
- * monitors.
- *
- * @param millis
- * the length of time to sleep in milliseconds
- *
- * @param nanos
- * {@code 0-999999} additional nanoseconds to sleep
- *
- * @throws IllegalArgumentException
- * if the value of {@code millis} is negative, or the value of
- * {@code nanos} is not in the range {@code 0-999999}
- *
- * @throws InterruptedException
- * if any thread has interrupted the current thread. The
- * <i>interrupted status</i> of the current thread is
- * cleared when this exception is thrown.
- */
- public static void sleep(long millis, int nanos)
- throws InterruptedException {
- if (millis < 0) {
- throw new IllegalArgumentException("timeout value is negative");
- }
- if (nanos < 0 || nanos > 999999) {
- throw new IllegalArgumentException(
- "nanosecond timeout value out of range");
- }
- if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
- millis++;
- }
- sleep(millis);
- }
- /**
- * Initializes a Thread.
- *
- * @param g the Thread group
- * @param target the object whose run() method gets called
- * @param name the name of the new Thread
- * @param stackSize the desired stack size for the new thread, or
- * zero to indicate that this parameter is to be ignored.
- */
- private void init(ThreadGroup g, Runnable target, String name,
- long stackSize) {
- if (name == null) {
- throw new NullPointerException("name cannot be null");
- }
- Thread parent = currentThread();
- SecurityManager security = System.getSecurityManager();
- if (g == null) {
- /* Determine if it's an applet or not */
- /* If there is a security manager, ask the security manager
- what to do. */
- if (security != null) {
- g = security.getThreadGroup();
- }
- /* If the security doesn't have a strong opinion of the matter
- use the parent thread group. */
- if (g == null) {
- g = parent.getThreadGroup();
- }
- }
- /* checkAccess regardless of whether or not threadgroup is
- explicitly passed in. */
- g.checkAccess();
- /*
- * Do we have the required permissions?
- */
- if (security != null) {
- if (isCCLOverridden(getClass())) {
- security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
- }
- }
- g.addUnstarted();
- this.group = g;
- this.daemon = parent.isDaemon();
- this.priority = parent.getPriority();
- this.name = name.toCharArray();
- if (security == null || isCCLOverridden(parent.getClass()))
- this.contextClassLoader = parent.getContextClassLoader();
- else
- this.contextClassLoader = parent.contextClassLoader;
- this.inheritedAccessControlContext = AccessController.getContext();
- this.target = target;
- setPriority(priority);
- if (parent.inheritableThreadLocals != null)
- this.inheritableThreadLocals =
- ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
- /* Stash the specified stack size in case the VM cares */
- this.stackSize = stackSize;
- /* Set thread ID */
- tid = nextThreadID();
- }
- /**
- * Throws CloneNotSupportedException as a Thread can not be meaningfully
- * cloned. Construct a new Thread instead.
- *
- * @throws CloneNotSupportedException
- * always
- */
- @Override
- protected Object clone() throws CloneNotSupportedException {
- throw new CloneNotSupportedException();
- }
- /**
- * Allocates a new {@code Thread} object. This constructor has the same
- * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
- * {@code (null, null, gname)}, where {@code gname} is a newly generated
- * name. Automatically generated names are of the form
- * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
- */
- public Thread() {
- init(null, null, "Thread-" + nextThreadNum(), 0);
- }
- /**
- * Allocates a new {@code Thread} object. This constructor has the same
- * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
- * {@code (null, target, gname)}, where {@code gname} is a newly generated
- * name. Automatically generated names are of the form
- * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
- *
- * @param target
- * the object whose {@code run} method is invoked when this thread
- * is started. If {@code null}, this classes {@code run} method does
- * nothing.
- */
- public Thread(Runnable target) {
- init(null, target, "Thread-" + nextThreadNum(), 0);
- }
- /**
- * Allocates a new {@code Thread} object. This constructor has the same
- * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
- * {@code (group, target, gname)} ,where {@code gname} is a newly generated
- * name. Automatically generated names are of the form
- * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
- *
- * @param group
- * the thread group. If {@code null} and there is a security
- * manager, the group is determined by {@linkplain
- * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
- * If there is not a security manager or {@code
- * SecurityManager.getThreadGroup()} returns {@code null}, the group
- * is set to the current thread's thread group.
- *
- * @param target
- * the object whose {@code run} method is invoked when this thread
- * is started. If {@code null}, this thread's run method is invoked.
- *
- * @throws SecurityException
- * if the current thread cannot create a thread in the specified
- * thread group
- */
- public Thread(ThreadGroup group, Runnable target) {
- init(group, target, "Thread-" + nextThreadNum(), 0);
- }
- /**
- * Allocates a new {@code Thread} object. This constructor has the same
- * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
- * {@code (null, null, name)}.
- *
- * @param name
- * the name of the new thread
- */
- public Thread(String name) {
- init(null, null, name, 0);
- }
- /**
- * Allocates a new {@code Thread} object. This constructor has the same
- * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
- * {@code (group, null, name)}.
- *
- * @param group
- * the thread group. If {@code null} and there is a security
- * manager, the group is determined by {@linkplain
- * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
- * If there is not a security manager or {@code
- * SecurityManager.getThreadGroup()} returns {@code null}, the group
- * is set to the current thread's thread group.
- *
- * @param name
- * the name of the new thread
- *
- * @throws SecurityException
- * if the current thread cannot create a thread in the specified
- * thread group
- */
- public Thread(ThreadGroup group, String name) {
- init(group, null, name, 0);
- }
- /**
- * Allocates a new {@code Thread} object. This constructor has the same
- * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
- * {@code (null, target, name)}.
- *
- * @param target
- * the object whose {@code run} method is invoked when this thread
- * is started. If {@code null}, this thread's run method is invoked.
- *
- * @param name
- * the name of the new thread
- */
- public Thread(Runnable target, String name) {
- init(null, target, name, 0);
- }
- /**
- * Allocates a new {@code Thread} object so that it has {@code target}
- * as its run object, has the specified {@code name} as its name,
- * and belongs to the thread group referred to by {@code group}.
- *
- * <p>If there is a security manager, its
- * {@link SecurityManager#checkAccess(ThreadGroup) checkAccess}
- * method is invoked with the ThreadGroup as its argument.
- *
- * <p>In addition, its {@code checkPermission} method is invoked with
- * the {@code RuntimePermission("enableContextClassLoaderOverride")}
- * permission when invoked directly or indirectly by the constructor
- * of a subclass which overrides the {@code getContextClassLoader}
- * or {@code setContextClassLoader} methods.
- *
- * <p>The priority of the newly created thread is set equal to the
- * priority of the thread creating it, that is, the currently running
- * thread. The method {@linkplain #setPriority setPriority} may be
- * used to change the priority to a new value.
- *
- * <p>The newly created thread is initially marked as being a daemon
- * thread if and only if the thread creating it is currently marked
- * as a daemon thread. The method {@linkplain #setDaemon setDaemon}
- * may be used to change whether or not a thread is a daemon.
- *
- * @param group
- * the thread group. If {@code null} and there is a security
- * manager, the group is determined by {@linkplain
- * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
- * If there is not a security manager or {@code
- * SecurityManager.getThreadGroup()} returns {@code null}, the group
- * is set to the current thread's thread group.
- *
- * @param target
- * the object whose {@code run} method is invoked when this thread
- * is started. If {@code null}, this thread's run method is invoked.
- *
- * @param name
- * the name of the new thread
- *
- * @throws SecurityException
- * if the current thread cannot create a thread in the specified
- * thread group or cannot override the context class loader methods.
- */
- public Thread(ThreadGroup group, Runnable target, String name) {
- init(group, target, name, 0);
- }
- /**
- * Allocates a new {@code Thread} object so that it has {@code target}
- * as its run object, has the specified {@code name} as its name,
- * and belongs to the thread group referred to by {@code group}, and has
- * the specified <i>stack size</i>.
- *
- * <p>This constructor is identical to {@link
- * #Thread(ThreadGroup,Runnable,String)} with the exception of the fact
- * that it allows the thread stack size to be specified. The stack size
- * is the approximate number of bytes of address space that the virtual
- * machine is to allocate for this thread's stack. <b>The effect of the
- * {@code stackSize} parameter, if any, is highly platform dependent.</b>
- *
- * <p>On some platforms, specifying a higher value for the
- * {@code stackSize} parameter may allow a thread to achieve greater
- * recursion depth before throwing a {@link *Error}.
- * Similarly, specifying a lower value may allow a greater number of
- * threads to exist concurrently without throwing an {@link
- * OutOfMemoryError} (or other internal error). The details of
- * the relationship between the value of the <tt>stackSize</tt> parameter
- * and the maximum recursion depth and concurrency level are
- * platform-dependent. <b>On some platforms, the value of the
- * {@code stackSize} parameter may have no effect whatsoever.</b>
- *
- * <p>The virtual machine is free to treat the {@code stackSize}
- * parameter as a suggestion. If the specified value is unreasonably low
- * for the platform, the virtual machine may instead use some
- * platform-specific minimum value; if the specified value is unreasonably
- * high, the virtual machine may instead use some platform-specific
- * maximum. Likewise, the virtual machine is free to round the specified
- * value up or down as it sees fit (or to ignore it completely).
- *
- * <p>Specifying a value of zero for the {@code stackSize} parameter will
- * cause this constructor to behave exactly like the
- * {@code Thread(ThreadGroup, Runnable, String)} constructor.
- *
- * <p><i>Due to the platform-dependent nature of the behavior of this
- * constructor, extreme care should be exercised in its use.
- * The thread stack size necessary to perform a given computation will
- * likely vary from one JRE implementation to another. In light of this
- * variation, careful tuning of the stack size parameter may be required,
- * and the tuning may need to be repeated for each JRE implementation on
- * which an application is to run.</i>
- *
- * <p>Implementation note: Java platform implementers are encouraged to
- * document their implementation's behavior with respect to the
- * {@code stackSize} parameter.
- *
- *
- * @param group
- * the thread group. If {@code null} and there is a security
- * manager, the group is determined by {@linkplain
- * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
- * If there is not a security manager or {@code
- * SecurityManager.getThreadGroup()} returns {@code null}, the group
- * is set to the current thread's thread group.
- *
- * @param target
- * the object whose {@code run} method is invoked when this thread
- * is started. If {@code null}, this thread's run method is invoked.
- *
- * @param name
- * the name of the new thread
- *
- * @param stackSize
- * the desired stack size for the new thread, or zero to indicate
- * that this parameter is to be ignored.
- *
- * @throws SecurityException
- * if the current thread cannot create a thread in the specified
- * thread group
- *
- * @since 1.4
- */
- public Thread(ThreadGroup group, Runnable target, String name,
- long stackSize) {
- init(group, target, name, stackSize);
- }
- /**
- * Causes this thread to begin execution; the Java Virtual Machine
- * calls the <code>run</code> method of this thread.
- * <p>
- * The result is that two threads are running concurrently: the
- * current thread (which returns from the call to the
- * <code>start</code> method) and the other thread (which executes its
- * <code>run</code> method).
- * <p>
- * It is never legal to start a thread more than once.
- * In particular, a thread may not be restarted once it has completed
- * execution.
- *
- * @exception IllegalThreadStateException if the thread was already
- * started.
- * @see #run()
- * @see #stop()
- */
- public synchronized void start() {
- /**
- * This method is not invoked for the main method thread or "system"
- * group threads created/set up by the VM. Any new functionality added
- * to this method in the future may have to also be added to the VM.
- *
- * A zero status value corresponds to state "NEW".
- */
- if (threadStatus != 0)
- throw new IllegalThreadStateException();
- /* Notify the group that this thread is about to be started
- * so that it can be added to the group's list of threads
- * and the group's unstarted count can be decremented. */
- group.add(this);
- boolean started = false;
- try {
- start0();
- started = true;
- } finally {
- try {
- if (!started) {
- group.threadStartFailed(this);
- }
- } catch (Throwable ignore) {
- /* do nothing. If start0 threw a Throwable then
- it will be passed up the call stack */
- }
- }
- }
- private native void start0();
- /**
- * If this thread was constructed using a separate
- * <code>Runnable</code> run object, then that
- * <code>Runnable</code> object's <code>run</code> method is called;
- * otherwise, this method does nothing and returns.
- * <p>
- * Subclasses of <code>Thread</code> should override this method.
- *
- * @see #start()
- * @see #stop()
- * @see #Thread(ThreadGroup, Runnable, String)
- */
- @Override
- public void run() {
- if (target != null) {
- target.run();
- }
- }
- /**
- * This method is called by the system to give a Thread
- * a chance to clean up before it actually exits.
- */
- private void exit() {
- if (group != null) {
- group.threadTerminated(this);
- group = null;
- }
- /* Aggressively null out all reference fields: see bug 4006245 */
- target = null;
- /* Speed the release of some of these resources */
- threadLocals = null;
- inheritableThreadLocals = null;
- inheritedAccessControlContext = null;
- blocker = null;
- uncaughtExceptionHandler = null;
- }
- /**
- * Forces the thread to stop executing.
- * <p>
- * If there is a security manager installed, its <code>checkAccess</code>
- * method is called with <code>this</code>
- * as its argument. This may result in a
- * <code>SecurityException</code> being raised (in the current thread).
- * <p>
- * If this thread is different from the current thread (that is, the current
- * thread is trying to stop a thread other than itself), the
- * security manager's <code>checkPermission</code> method (with a
- * <code>RuntimePermission("stopThread")</code> argument) is called in
- * addition.
- * Again, this may result in throwing a
- * <code>SecurityException</code> (in the current thread).
- * <p>
- * The thread represented by this thread is forced to stop whatever
- * it is doing abnormally and to throw a newly created
- * <code>ThreadDeath</code> object as an exception.
- * <p>
- * It is permitted to stop a thread that has not yet been started.
- * If the thread is eventually started, it immediately terminates.
- * <p>
- * An application should not normally try to catch
- * <code>ThreadDeath</code> unless it must do some extraordinary
- * cleanup operation (note that the throwing of
- * <code>ThreadDeath</code> causes <code>finally</code> clauses of
- * <code>try</code> statements to be executed before the thread
- * officially dies). If a <code>catch</code> clause catches a
- * <code>ThreadDeath</code> object, it is important to rethrow the
- * object so that the thread actually dies.
- * <p>
- * The top-level error handler that reacts to otherwise uncaught
- * exceptions does not print out a message or otherwise notify the
- * application if the uncaught exception is an instance of
- * <code>ThreadDeath</code>.
- *
- * @exception SecurityException if the current thread cannot
- * modify this thread.
- * @see #interrupt()
- * @see #checkAccess()
- * @see #run()
- * @see #start()
- * @see ThreadDeath
- * @see ThreadGroup#uncaughtException(Thread,Throwable)
- * @see SecurityManager#checkAccess(Thread)
- * @see SecurityManager#checkPermission
- * @deprecated This method is inherently unsafe. Stopping a thread with
- * Thread.stop causes it to unlock all of the monitors that it
- * has locked (as a natural consequence of the unchecked
- * <code>ThreadDeath</code> exception propagating up the stack). If
- * any of the objects previously protected by these monitors were in
- * an inconsistent state, the damaged objects become visible to
- * other threads, potentially resulting in arbitrary behavior. Many
- * uses of <code>stop</code> should be replaced by code that simply
- * modifies some variable to indicate that the target thread should
- * stop running. The target thread should check this variable
- * regularly, and return from its run method in an orderly fashion
- * if the variable indicates that it is to stop running. If the
- * target thread waits for long periods (on a condition variable,
- * for example), the <code>interrupt</code> method should be used to
- * interrupt the wait.
- * For more information, see
- * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
- * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
- */
- @Deprecated
- public final void stop() {
- stop(new ThreadDeath());
- }
- /**
- * Forces the thread to stop executing.
- * <p>
- * If there is a security manager installed, the <code>checkAccess</code>
- * method of this thread is called, which may result in a
- * <code>SecurityException</code> being raised (in the current thread).
- * <p>
- * If this thread is different from the current thread (that is, the current
- * thread is trying to stop a thread other than itself) or
- * <code>obj</code> is not an instance of <code>ThreadDeath</code>, the
- * security manager's <code>checkPermission</code> method (with the
- * <code>RuntimePermission("stopThread")</code> argument) is called in
- * addition.
- * Again, this may result in throwing a
- * <code>SecurityException</code> (in the current thread).
- * <p>
- * If the argument <code>obj</code> is null, a
- * <code>NullPointerException</code> is thrown (in the current thread).
- * <p>
- * The thread represented by this thread is forced to stop
- * whatever it is doing abnormally and to throw the
- * <code>Throwable</code> object <code>obj</code> as an exception. This
- * is an unusual action to take; normally, the <code>stop</code> method
- * that takes no arguments should be used.
- * <p>
- * It is permitted to stop a thread that has not yet been started.
- * If the thread is eventually started, it immediately terminates.
- *
- * @param obj the Throwable object to be thrown.
- * @exception SecurityException if the current thread cannot modify
- * this thread.
- * @throws NullPointerException if obj is <tt>null</tt>.
- * @see #interrupt()
- * @see #checkAccess()
- * @see #run()
- * @see #start()
- * @see #stop()
- * @see SecurityManager#checkAccess(Thread)
- * @see SecurityManager#checkPermission
- * @deprecated This method is inherently unsafe. See {@link #stop()}
- * for details. An additional danger of this
- * method is that it may be used to generate exceptions that the
- * target thread is unprepared to handle (including checked
- * exceptions that the thread could not possibly throw, were it
- * not for this method).
- * For more information, see
- * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
- * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
- */
- @Deprecated
- public final synchronized void stop(Throwable obj) {
- if (obj == null)
- throw new NullPointerException();
- SecurityManager security = System.getSecurityManager();
- if (security != null) {
- checkAccess();
- if ((this != Thread.currentThread()) ||
- (!(obj instanceof ThreadDeath))) {
- security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
- }
- }
- // A zero status value corresponds to "NEW", it can't change to
- // not-NEW because we hold the lock.
- if (threadStatus != 0) {
- resume(); // Wake up thread if it was suspended; no-op otherwise
- }
- // The VM can handle all thread states
- stop0(obj);
- }
- /**
- * Interrupts this thread.
- *
- * <p> Unless the current thread is interrupting itself, which is
- * always permitted, the {@link #checkAccess() checkAccess} method
- * of this thread is invoked, which may cause a {@link
- * SecurityException} to be thrown.
- *
- * <p> If this thread is blocked in an invocation of the {@link
- * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
- * Object#wait(long, int) wait(long, int)} methods of the {@link Object}
- * class, or of the {@link #join()}, {@link #join(long)}, {@link
- * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
- * methods of this class, then its interrupt status will be cleared and it
- * will receive an {@link InterruptedException}.
- *
- * <p> If this thread is blocked in an I/O operation upon an {@link
- * java.nio.channels.InterruptibleChannel </code>interruptible
- * channel<code>} then the channel will be closed, the thread's interrupt
- * status will be set, and the thread will receive a {@link
- * java.nio.channels.ClosedByInterruptException}.
- *
- * <p> If this thread is blocked in a {@link java.nio.channels.Selector}
- * then the thread's interrupt status will be set and it will return
- * immediately from the selection operation, possibly with a non-zero
- * value, just as if the selector's {@link
- * java.nio.channels.Selector#wakeup wakeup} method were invoked.
- *
- * <p> If none of the previous conditions hold then this thread's interrupt
- * status will be set. </p>
- *
- * <p> Interrupting a thread that is not alive need not have any effect.
- *
- * @throws SecurityException
- * if the current thread cannot modify this thread
- *
- * @revised 6.0
- * @spec JSR-51
- */
- public void interrupt() {
- if (this != Thread.currentThread())
- checkAccess();
- synchronized (blockerLock) {
- Interruptible b = blocker;
- if (b != null) {
- interrupt0(); // Just to set the interrupt flag
- b.interrupt(this);
- return;
- }
- }
- interrupt0();
- }
- /**
- * Tests whether the current thread has been interrupted. The
- * <i>interrupted status</i> of the thread is cleared by this method. In
- * other words, if this method were to be called twice in succession, the
- * second call would return false (unless the current thread were
- * interrupted again, after the first call had cleared its interrupted
- * status and before the second call had examined it).
- *
- * <p>A thread interruption ignored because a thread was not alive
- * at the time of the interrupt will be reflected by this method
- * returning false.
- *
- * @return <code>true</code> if the current thread has been interrupted;
- * <code>false</code> otherwise.
- * @see #isInterrupted()
- * @revised 6.0
- */
- public static boolean interrupted() {
- return currentThread().isInterrupted(true);
- }
- /**
- * Tests whether this thread has been interrupted. The <i>interrupted
- * status</i> of the thread is unaffected by this method.
- *
- * <p>A thread interruption ignored because a thread was not alive
- * at the time of the interrupt will be reflected by this method
- * returning false.
- *
- * @return <code>true</code> if this thread has been interrupted;
- * <code>false</code> otherwise.
- * @see #interrupted()
- * @revised 6.0
- */
- public boolean isInterrupted() {
- return isInterrupted(false);
- }
- /**
- * Tests if some Thread has been interrupted. The interrupted state
- * is reset or not based on the value of ClearInterrupted that is
- * passed.
- */
- private native boolean isInterrupted(boolean ClearInterrupted);
- /**
- * Throws {@link NoSuchMethodError}.
- *
- * @deprecated This method was originally designed to destroy this
- * thread without any cleanup. Any monitors it held would have
- * remained locked. However, the method was never implemented.
- * If if were to be implemented, it would be deadlock-prone in
- * much the manner of {@link #suspend}. If the target thread held
- * a lock protecting a critical system resource when it was
- * destroyed, no thread could ever access this resource again.
- * If another thread ever attempted to lock this resource, deadlock
- * would result. Such deadlocks typically manifest themselves as
- * "frozen" processes. For more information, see
- * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">
- * Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
- * @throws NoSuchMethodError always
- */
- @Deprecated
- public void destroy() {
- throw new NoSuchMethodError();
- }
- /**
- * Tests if this thread is alive. A thread is alive if it has
- * been started and has not yet died.
- *
- * @return <code>true</code> if this thread is alive;
- * <code>false</code> otherwise.
- */
- public final native boolean isAlive();
- /**
- * Suspends this thread.
- * <p>
- * First, the <code>checkAccess</code> method of this thread is called
- * with no arguments. This may result in throwing a
- * <code>SecurityException </code>(in the current thread).
- * <p>
- * If the thread is alive, it is suspended and makes no further
- * progress unless and until it is resumed.
- *
- * @exception SecurityException if the current thread cannot modify
- * this thread.
- * @see #checkAccess
- * @deprecated This method has been deprecated, as it is
- * inherently deadlock-prone. If the target thread holds a lock on the
- * monitor protecting a critical system resource when it is suspended, no
- * thread can access this resource until the target thread is resumed. If
- * the thread that would resume the target thread attempts to lock this
- * monitor prior to calling <code>resume</code>, deadlock results. Such
- * deadlocks typically manifest themselves as "frozen" processes.
- * For more information, see
- * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
- * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
- */
- @Deprecated
- public final void suspend() {
- checkAccess();
- suspend0();
- }
- /**
- * Resumes a suspended thread.
- * <p>
- * First, the <code>checkAccess</code> method of this thread is called
- * with no arguments. This may result in throwing a
- * <code>SecurityException</code> (in the current thread).
- * <p>
- * If the thread is alive but suspended, it is resumed and is
- * permitted to make progress in its execution.
- *
- * @exception SecurityException if the current thread cannot modify this
- * thread.
- * @see #checkAccess
- * @see #suspend()
- * @deprecated This method exists solely for use with {@link #suspend},
- * which has been deprecated because it is deadlock-prone.
- * For more information, see
- * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
- * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
- */
- @Deprecated
- public final void resume() {
- checkAccess();
- resume0();
- }
- /**
- * Changes the priority of this thread.
- * <p>
- * First the <code>checkAccess</code> method of this thread is called
- * with no arguments. This may result in throwing a
- * <code>SecurityException</code>.
- * <p>
- * Otherwise, the priority of this thread is set to the smaller of
- * the specified <code>newPriority</code> and the maximum permitted
- * priority of the thread's thread group.
- *
- * @param newPriority priority to set this thread to
- * @exception IllegalArgumentException If the priority is not in the
- * range <code>MIN_PRIORITY</code> to
- * <code>MAX_PRIORITY</code>.
- * @exception SecurityException if the current thread cannot modify
- * this thread.
- * @see #getPriority
- * @see #checkAccess()
- * @see #getThreadGroup()
- * @see #MAX_PRIORITY
- * @see #MIN_PRIORITY
- * @see ThreadGroup#getMaxPriority()
- */
- public final void setPriority(int newPriority) {
- ThreadGroup g;
- checkAccess();
- if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
- throw new IllegalArgumentException();
- }
- if((g = getThreadGroup()) != null) {
- if (newPriority > g.getMaxPriority()) {
- newPriority = g.getMaxPriority();
- }
- setPriority0(priority = newPriority);
- }
- }
- /**
- * Returns this thread's priority.
- *
- * @return this thread's priority.
- * @see #setPriority
- */
- public final int getPriority() {
- return priority;
- }
- /**
- * Changes the name of this thread to be equal to the argument
- * <code>name</code>.
- * <p>
- * First the <code>checkAccess</code> method of this thread is called
- * with no arguments. This may result in throwing a
- * <code>SecurityException</code>.
- *
- * @param name the new name for this thread.
- * @exception SecurityException if the current thread cannot modify this
- * thread.
- * @see #getName
- * @see #checkAccess()
- */
- public final void setName(String name) {
- checkAccess();
- this.name = name.toCharArray();
- }
- /**
- * Returns this thread's name.
- *
- * @return this thread's name.
- * @see #setName(String)
- */
- public final String getName() {
- return String.valueOf(name);
- }
- /**
- * Returns the thread group to which this thread belongs.
- * This method returns null if this thread has died
- * (been stopped).
- *
- * @return this thread's thread group.
- */
- public final ThreadGroup getThreadGroup() {
- return group;
- }
- /**
- * Returns an estimate of the number of active threads in the current
- * thread's {@linkplain java.lang.ThreadGroup thread group} and its
- * subgroups. Recursively iterates over all subgroups in the current
- * thread's thread group.
- *
- * <p> The value returned is only an estimate because the number of
- * threads may change dynamically while this method traverses internal
- * data structures, and might be affected by the presence of certain
- * system threads. This method is intended primarily for debugging
- * and monitoring purposes.
- *
- * @return an estimate of the number of active threads in the current
- * thread's thread group and in any other thread group that
- * has the current thread's thread group as an ancestor
- */
- public static int activeCount() {
- return currentThread().getThreadGroup().activeCount();
- }
- /**
- * Copies into the specified array every active thread in the current
- * thread's thread group and its subgroups. This method simply
- * invokes the {@link java.lang.ThreadGroup#enumerate(Thread[])}
- * method of the current thread's thread group.
- *
- * <p> An application might use the {@linkplain #activeCount activeCount}
- * method to get an estimate of how big the array should be, however
- * <i>if the array is too short to hold all the threads, the extra threads
- * are silently ignored.</i> If it is critical to obtain every active
- * thread in the current thread's thread group and its subgroups, the
- * invoker should verify that the returned int value is strictly less
- * than the length of {@code tarray}.
- *
- * <p> Due to the inherent race condition in this method, it is recommended
- * that the method only be used for debugging and monitoring purposes.
- *
- * @param tarray
- * an array into which to put the list of threads
- *
- * @return the number of threads put into the array
- *
- * @throws SecurityException
- * if {@link java.lang.ThreadGroup#checkAccess} determines that
- * the current thread cannot access its thread group
- */
- public static int enumerate(Thread tarray[]) {
- return currentThread().getThreadGroup().enumerate(tarray);
- }
- /**
- * Counts the number of stack frames in this thread. The thread must
- * be suspended.
- *
- * @return the number of stack frames in this thread.
- * @exception IllegalThreadStateException if this thread is not
- * suspended.
- * @deprecated The definition of this call depends on {@link #suspend},
- * which is deprecated. Further, the results of this call
- * were never well-defined.
- */
- @Deprecated
- public native int countStackFrames();
- /**
- * Waits at most {@code millis} milliseconds for this thread to
- * die. A timeout of {@code 0} means to wait forever.
- *
- * <p> This implementation uses a loop of {@code this.wait} calls
- * conditioned on {@code this.isAlive}. As a thread terminates the
- * {@code this.notifyAll} method is invoked. It is recommended that
- * applications not use {@code wait}, {@code notify}, or
- * {@code notifyAll} on {@code Thread} instances.
- *
- * @param millis
- * the time to wait in milliseconds
- *
- * @throws IllegalArgumentException
- * if the value of {@code millis} is negative
- *
- * @throws InterruptedException
- * if any thread has interrupted the current thread. The
- * <i>interrupted status</i> of the current thread is
- * cleared when this exception is thrown.
- */
- public final synchronized void join(long millis)
- throws InterruptedException {
- long base = System.currentTimeMillis();
- long now = 0;
- if (millis < 0) {
- throw new IllegalArgumentException("timeout value is negative");
- }
- if (millis == 0) {
- while (isAlive()) {
- wait(0);
- }
- } else {
- while (isAlive()) {
- long delay = millis - now;
- if (delay <= 0) {
- break;
- }
- wait(delay);
- now = System.currentTimeMillis() - base;
- }
- }
- }
- /**
- * Waits at most {@code millis} milliseconds plus
- * {@code nanos} nanoseconds for this thread to die.
- *
- * <p> This implementation uses a loop of {@code this.wait} calls
- * conditioned on {@code this.isAlive}. As a thread terminates the
- * {@code this.notifyAll} method is invoked. It is recommended that
- * applications not use {@code wait}, {@code notify}, or
- * {@code notifyAll} on {@code Thread} instances.
- *
- * @param millis
- * the time to wait in milliseconds
- *
- * @param nanos
- * {@code 0-999999} additional nanoseconds to wait
- *
- * @throws IllegalArgumentException
- * if the value of {@code millis} is negative, or the value
- * of {@code nanos} is not in the range {@code 0-999999}
- *
- * @throws InterruptedException
- * if any thread has interrupted the current thread. The
- * <i>interrupted status</i> of the current thread is
- * cleared when this exception is thrown.
- */
- public final synchronized void join(long millis, int nanos)
- throws InterruptedException {
- if (millis < 0) {
- throw new IllegalArgumentException("timeout value is negative");
- }
- if (nanos < 0 || nanos > 999999) {
- throw new IllegalArgumentException(
- "nanosecond timeout value out of range");
- }
- if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
- millis++;
- }
- join(millis);
- }
- /**
- * Waits for this thread to die.
- *
- * <p> An invocation of this method behaves in exactly the same
- * way as the invocation
- *
- * <blockquote>
- * {@linkplain #join(long) join}{@code (0)}
- * </blockquote>
- *
- * @throws InterruptedException
- * if any thread has interrupted the current thread. The
- * <i>interrupted status</i> of the current thread is
- * cleared when this exception is thrown.
- */
- public final void join() throws InterruptedException {
- join(0);
- }
- /**
- * Prints a stack trace of the current thread to the standard error stream.
- * This method is used only for debugging.
- *
- * @see Throwable#printStackTrace()
- */
- public static void dumpStack() {
- new Exception("Stack trace").printStackTrace();
- }
- /**
- * Marks this thread as either a {@linkplain #isDaemon daemon} thread
- * or a user thread. The Java Virtual Machine exits when the only
- * threads running are all daemon threads.
- *
- * <p> This method must be invoked before the thread is started.
- *
- * @param on
- * if {@code true}, marks this thread as a daemon thread
- *
- * @throws IllegalThreadStateException
- * if this thread is {@linkplain #isAlive alive}
- *
- * @throws SecurityException
- * if {@link #checkAccess} determines that the current
- * thread cannot modify this thread
- */
- public final void setDaemon(boolean on) {
- checkAccess();
- if (isAlive()) {
- throw new IllegalThreadStateException();
- }
- daemon = on;
- }
- /**
- * Tests if this thread is a daemon thread.
- *
- * @return <code>true</code> if this thread is a daemon thread;
- * <code>false</code> otherwise.
- * @see #setDaemon(boolean)
- */
- public final boolean isDaemon() {
- return daemon;
- }
- /**
- * Determines if the currently running thread has permission to
- * modify this thread.
- * <p>
- * If there is a security manager, its <code>checkAccess</code> method
- * is called with this thread as its argument. This may result in
- * throwing a <code>SecurityException</code>.
- *
- * @exception SecurityException if the current thread is not allowed to
- * access this thread.
- * @see SecurityManager#checkAccess(Thread)
- */
- public final void checkAccess() {
- SecurityManager security = System.getSecurityManager();
- if (security != null) {
- security.checkAccess(this);
- }
- }
- /**
- * Returns a string representation of this thread, including the
- * thread's name, priority, and thread group.
- *
- * @return a string representation of this thread.
- */
- public String toString() {
- ThreadGroup group = getThreadGroup();
- if (group != null) {
- return "Thread[" + getName() + "," + getPriority() + "," +
- group.getName() + "]";
- } else {
- return "Thread[" + getName() + "," + getPriority() + "," +
- "" + "]";
- }
- }
- /**
- * Returns the context ClassLoader for this Thread. The context
- * ClassLoader is provided by the creator of the thread for use
- * by code running in this thread when loading classes and resources.
- * If not {@linkplain #setContextClassLoader set}, the default is the
- * ClassLoader context of the parent Thread. The context ClassLoader of the
- * primordial thread is typically set to the class loader used to load the
- * application.
- *
- * <p>If a security manager is present, and the invoker's class loader is not
- * {@code null} and is not the same as or an ancestor of the context class
- * loader, then this method invokes the security manager's {@link
- * SecurityManager#checkPermission(java.security.Permission) checkPermission}
- * method with a {@link RuntimePermission RuntimePermission}{@code
- * ("getClassLoader")} permission to verify that retrieval of the context
- * class loader is permitted.
- *
- * @return the context ClassLoader for this Thread, or {@code null}
- * indicating the system class loader (or, failing that, the
- * bootstrap class loader)
- *
- * @throws SecurityException
- * if the current thread cannot get the context ClassLoader
- *
- * @since 1.2
- */
- public ClassLoader getContextClassLoader() {
- if (contextClassLoader == null)
- return null;
- SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
- ClassLoader ccl = ClassLoader.getCallerClassLoader();
- if (ccl != null && ccl != contextClassLoader &&
- !contextClassLoader.isAncestor(ccl)) {
- sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
- }
- }
- return contextClassLoader;
- }
- /**
- * Sets the context ClassLoader for this Thread. The context
- * ClassLoader can be set when a thread is created, and allows
- * the creator of the thread to provide the appropriate class loader,
- * through {@code getContextClassLoader}, to code running in the thread
- * when loading classes and resources.
- *
- * <p>If a security manager is present, its {@link
- * SecurityManager#checkPermission(java.security.Permission) checkPermission}
- * method is invoked with a {@link RuntimePermission RuntimePermission}{@code
- * ("setContextClassLoader")} permission to see if setting the context
- * ClassLoader is permitted.
- *
- * @param cl
- * the context ClassLoader for this Thread, or null indicating the
- * system class loader (or, failing that, the bootstrap class loader)
- *
- * @throws SecurityException
- * if the current thread cannot set the context ClassLoader
- *
- * @since 1.2
- */
- public void setContextClassLoader(ClassLoader cl) {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
- sm.checkPermission(new RuntimePermission("setContextClassLoader"));
- }
- contextClassLoader = cl;
- }
- /**
- * Returns <tt>true</tt> if and only if the current thread holds the
- * monitor lock on the specified object.
- *
- * <p>This method is designed to allow a program to assert that
- * the current thread already holds a specified lock:
- * <pre>
- * assert Thread.holdsLock(obj);
- * </pre>
- *
- * @param obj the object on which to test lock ownership
- * @throws NullPointerException if obj is <tt>null</tt>
- * @return <tt>true</tt> if the current thread holds the monitor lock on
- * the specified object.
- * @since 1.4
- */
- public static native boolean holdsLock(Object obj);
- private static final StackTraceElement[] EMPTY_STACK_TRACE
- = new StackTraceElement[0];
- /**
- * Returns an array of stack trace elements representing the stack dump
- * of this thread. This method will return a zero-length array if
- * this thread has not started, has started but has not yet been
- * scheduled to run by the system, or has terminated.
- * If the returned array is of non-zero length then the first element of
- * the array represents the top of the stack, which is the most recent
- * method invocation in the sequence. The last element of the array
- * represents the bottom of the stack, which is the least recent method
- * invocation in the sequence.
- *
- * <p>If there is a security manager, and this thread is not
- * the current thread, then the security manager's
- * <tt>checkPermission</tt> method is called with a
- * <tt>RuntimePermission("getStackTrace")</tt> permission
- * to see if it's ok to get the stack trace.
- *
- * <p>Some virtual machines may, under some circumstances, omit one
- * or more stack frames from the stack trace. In the extreme case,
- * a virtual machine that has no stack trace information concerning
- * this thread is permitted to return a zero-length array from this
- * method.
- *
- * @return an array of <tt>StackTraceElement</tt>,
- * each represents one stack frame.
- *
- * @throws SecurityException
- * if a security manager exists and its
- * <tt>checkPermission</tt> method doesn't allow
- * getting the stack trace of thread.
- * @see SecurityManager#checkPermission
- * @see RuntimePermission
- * @see Throwable#getStackTrace
- *
- * @since 1.5
- */
- public StackTraceElement[] getStackTrace() {
- if (this != Thread.currentThread()) {
- // check for getStackTrace permission
- SecurityManager security = System.getSecurityManager();
- if (security != null) {
- security.checkPermission(
- SecurityConstants.GET_STACK_TRACE_PERMISSION);
- }
- // optimization so we do not call into the vm for threads that
- // have not yet started or have terminated
- if (!isAlive()) {
- return EMPTY_STACK_TRACE;
- }
- StackTraceElement[][] stackTraceArray = dumpThreads(new Thread[] {this});
- StackTraceElement[] stackTrace = stackTraceArray[0];
- // a thread that was alive during the previous isAlive call may have
- // since terminated, therefore not having a stacktrace.
- if (stackTrace == null) {
- stackTrace = EMPTY_STACK_TRACE;
- }
- return stackTrace;
- } else {
- // Don't need JVM help for current thread
- return (new Exception()).getStackTrace();
- }
- }
- /**
- * Returns a map of stack traces for all live threads.
- * The map keys are threads and each map value is an array of
- * <tt>StackTraceElement</tt> that represents the stack dump
- * of the corresponding <tt>Thread</tt>.
- * The returned stack traces are in the format specified for
- * the {@link #getStackTrace getStackTrace} method.
- *
- * <p>The threads may be executing while this method is called.
- * The stack trace of each thread only represents a snapshot and
- * each stack trace may be obtained at different time. A zero-length
- * array will be returned in the map value if the virtual machine has
- * no stack trace information about a thread.
- *
- * <p>If there is a security manager, then the security manager's
- * <tt>checkPermission</tt> method is called with a
- * <tt>RuntimePermission("getStackTrace")</tt> permission as well as
- * <tt>RuntimePermission("modifyThreadGroup")</tt> permission
- * to see if it is ok to get the stack trace of all threads.
- *
- * @return a <tt>Map</tt> from <tt>Thread</tt> to an array of
- * <tt>StackTraceElement</tt> that represents the stack trace of
- * the corresponding thread.
- *
- * @throws SecurityException
- * if a security manager exists and its
- * <tt>checkPermission</tt> method doesn't allow
- * getting the stack trace of thread.
- * @see #getStackTrace
- * @see SecurityManager#checkPermission
- * @see RuntimePermission
- * @see Throwable#getStackTrace
- *
- * @since 1.5
- */
- public static Map<Thread, StackTraceElement[]> getAllStackTraces() {
- // check for getStackTrace permission
- SecurityManager security = System.getSecurityManager();
- if (security != null) {
- security.checkPermission(
- SecurityConstants.GET_STACK_TRACE_PERMISSION);
- security.checkPermission(
- SecurityConstants.MODIFY_THREADGROUP_PERMISSION);
- }
- // Get a snapshot of the list of all threads
- Thread[] threads = getThreads();
- StackTraceElement[][] traces = dumpThreads(threads);
- Map<Thread, StackTraceElement[]> m = new HashMap<>(threads.length);
- for (int i = 0; i < threads.length; i++) {
- StackTraceElement[] stackTrace = traces[i];
- if (stackTrace != null) {
- m.put(threads[i], stackTrace);
- }
- // else terminated so we don't put it in the map
- }
- return m;
- }
- private static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION =
- new RuntimePermission("enableContextClassLoaderOverride");
- /** cache of subclass security audit results */
- /* Replace with ConcurrentReferenceHashMap when/if it appears in a future
- * release */
- private static class Caches {
- /** cache of subclass security audit results */
- static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
- new ConcurrentHashMap<>();
- /** queue for WeakReferences to audited subclasses */
- static final ReferenceQueue<Class<?>> subclassAuditsQueue =
- new ReferenceQueue<>();
- }
- /**
- * Verifies that this (possibly subclass) instance can be constructed
- * without violating security constraints: the subclass must not override
- * security-sensitive non-final methods, or else the
- * "enableContextClassLoaderOverride" RuntimePermission is checked.
- */
- private static boolean isCCLOverridden(Class cl) {
- if (cl == Thread.class)
- return false;
- processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
- WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
- Boolean result = Caches.subclassAudits.get(key);
- if (result == null) {
- result = Boolean.valueOf(auditSubclass(cl));
- Caches.subclassAudits.putIfAbsent(key, result);
- }
- return result.booleanValue();
- }
- /**
- * Performs reflective checks on given subclass to verify that it doesn't
- * override security-sensitive non-final methods. Returns true if the
- * subclass overrides any of the methods, false otherwise.
- */
- private static boolean auditSubclass(final Class subcl) {
- Boolean result = AccessController.doPrivileged(
- new PrivilegedAction<Boolean>() {
- public Boolean run() {
- for (Class cl = subcl;
- cl != Thread.class;
- cl = cl.getSuperclass())
- {
- try {
- cl.getDeclaredMethod("getContextClassLoader", new Class[0]);
- return Boolean.TRUE;
- } catch (NoSuchMethodException ex) {
- }
- try {
- Class[] params = {ClassLoader.class};
- cl.getDeclaredMethod("setContextClassLoader", params);
- return Boolean.TRUE;
- } catch (NoSuchMethodException ex) {
- }
- }
- return Boolean.FALSE;
- }
- }
- );
- return result.booleanValue();
- }
- private native static StackTraceElement[][] dumpThreads(Thread[] threads);
- private native static Thread[] getThreads();
- /**
- * Returns the identifier of this Thread. The thread ID is a positive
- * <tt>long</tt> number generated when this thread was created.
- * The thread ID is unique and remains unchanged during its lifetime.
- * When a thread is terminated, this thread ID may be reused.
- *
- * @return this thread's ID.
- * @since 1.5
- */
- public long getId() {
- return tid;
- }
- /**
- * A thread state. A thread can be in one of the following states:
- * <ul>
- * <li>{@link #NEW}<br>
- * A thread that has not yet started is in this state.
- * </li>
- * <li>{@link #RUNNABLE}<br>
- * A thread executing in the Java virtual machine is in this state.
- * </li>
- * <li>{@link #BLOCKED}<br>
- * A thread that is blocked waiting for a monitor lock
- * is in this state.
- * </li>
- * <li>{@link #WAITING}<br>
- * A thread that is waiting indefinitely for another thread to
- * perform a particular action is in this state.
- * </li>
- * <li>{@link #TIMED_WAITING}<br>
- * A thread that is waiting for another thread to perform an action
- * for up to a specified waiting time is in this state.
- * </li>
- * <li>{@link #TERMINATED}<br>
- * A thread that has exited is in this state.
- * </li>
- * </ul>
- *
- * <p>
- * A thread can be in only one state at a given point in time.
- * These states are virtual machine states which do not reflect
- * any operating system thread states.
- *
- * @since 1.5
- * @see #getState
- */
- public enum State {
- /**
- * Thread state for a thread which has not yet started.
- */
- NEW,
- /**
- * Thread state for a runnable thread. A thread in the runnable
- * state is executing in the Java virtual machine but it may
- * be waiting for other resources from the operating system
- * such as processor.
- */
- RUNNABLE,
- /**
- * Thread state for a thread blocked waiting for a monitor lock.
- * A thread in the blocked state is waiting for a monitor lock
- * to enter a synchronized block/method or
- * reenter a synchronized block/method after calling
- * {@link Object#wait() Object.wait}.
- */
- BLOCKED,
- /**
- * Thread state for a waiting thread.
- * A thread is in the waiting state due to calling one of the
- * following methods:
- * <ul>
- * <li>{@link Object#wait() Object.wait} with no timeout</li>
- * <li>{@link #join() Thread.join} with no timeout</li>
- * <li>{@link LockSupport#park() LockSupport.park}</li>
- * </ul>
- *
- * <p>A thread in the waiting state is waiting for another thread to
- * perform a particular action.
- *
- * For example, a thread that has called <tt>Object.wait()</tt>
- * on an object is waiting for another thread to call
- * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
- * that object. A thread that has called <tt>Thread.join()</tt>
- * is waiting for a specified thread to terminate.
- */
- WAITING,
- /**
- * Thread state for a waiting thread with a specified waiting time.
- * A thread is in the timed waiting state due to calling one of
- * the following methods with a specified positive waiting time:
- * <ul>
- * <li>{@link #sleep Thread.sleep}</li>
- * <li>{@link Object#wait(long) Object.wait} with timeout</li>
- * <li>{@link #join(long) Thread.join} with timeout</li>
- * <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
- * <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
- * </ul>
- */
- TIMED_WAITING,
- /**
- * Thread state for a terminated thread.
- * The thread has completed execution.
- */
- TERMINATED;
- }
- /**
- * Returns the state of this thread.
- * This method is designed for use in monitoring of the system state,
- * not for synchronization control.
- *
- * @return this thread's state.
- * @since 1.5
- */
- public State getState() {
- // get current thread state
- return sun.misc.VM.toThreadState(threadStatus);
- }
- // Added in JSR-166
- /**
- * Interface for handlers invoked when a <tt>Thread</tt> abruptly
- * terminates due to an uncaught exception.
- * <p>When a thread is about to terminate due to an uncaught exception
- * the Java Virtual Machine will query the thread for its
- * <tt>UncaughtExceptionHandler</tt> using
- * {@link #getUncaughtExceptionHandler} and will invoke the handler's
- * <tt>uncaughtException</tt> method, passing the thread and the
- * exception as arguments.
- * If a thread has not had its <tt>UncaughtExceptionHandler</tt>
- * explicitly set, then its <tt>ThreadGroup</tt> object acts as its
- * <tt>UncaughtExceptionHandler</tt>. If the <tt>ThreadGroup</tt> object
- * has no
- * special requirements for dealing with the exception, it can forward
- * the invocation to the {@linkplain #getDefaultUncaughtExceptionHandler
- * default uncaught exception handler}.
- *
- * @see #setDefaultUncaughtExceptionHandler
- * @see #setUncaughtExceptionHandler
- * @see ThreadGroup#uncaughtException
- * @since 1.5
- */
- public interface UncaughtExceptionHandler {
- /**
- * Method invoked when the given thread terminates due to the
- * given uncaught exception.
- * <p>Any exception thrown by this method will be ignored by the
- * Java Virtual Machine.
- * @param t the thread
- * @param e the exception
- */
- void uncaughtException(Thread t, Throwable e);
- }
- // null unless explicitly set
- private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
- // null unless explicitly set
- private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
- /**
- * Set the default handler invoked when a thread abruptly terminates
- * due to an uncaught exception, and no other handler has been defined
- * for that thread.
- *
- * <p>Uncaught exception handling is controlled first by the thread, then
- * by the thread's {@link ThreadGroup} object and finally by the default
- * uncaught exception handler. If the thread does not have an explicit
- * uncaught exception handler set, and the thread's thread group
- * (including parent thread groups) does not specialize its
- * <tt>uncaughtException</tt> method, then the default handler's
- * <tt>uncaughtException</tt> method will be invoked.
- * <p>By setting the default uncaught exception handler, an application
- * can change the way in which uncaught exceptions are handled (such as
- * logging to a specific device, or file) for those threads that would
- * already accept whatever "default" behavior the system
- * provided.
- *
- * <p>Note that the default uncaught exception handler should not usually
- * defer to the thread's <tt>ThreadGroup</tt> object, as that could cause
- * infinite recursion.
- *
- * @param eh the object to use as the default uncaught exception handler.
- * If <tt>null</tt> then there is no default handler.
- *
- * @throws SecurityException if a security manager is present and it
- * denies <tt>{@link RuntimePermission}
- * ("setDefaultUncaughtExceptionHandler")</tt>
- *
- * @see #setUncaughtExceptionHandler
- * @see #getUncaughtExceptionHandler
- * @see ThreadGroup#uncaughtException
- * @since 1.5
- */
- public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
- sm.checkPermission(
- new RuntimePermission("setDefaultUncaughtExceptionHandler")
- );
- }
- defaultUncaughtExceptionHandler = eh;
- }
- /**
- * Returns the default handler invoked when a thread abruptly terminates
- * due to an uncaught exception. If the returned value is <tt>null</tt>,
- * there is no default.
- * @since 1.5
- * @see #setDefaultUncaughtExceptionHandler
- */
- public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
- return defaultUncaughtExceptionHandler;
- }
- /**
- * Returns the handler invoked when this thread abruptly terminates
- * due to an uncaught exception. If this thread has not had an
- * uncaught exception handler explicitly set then this thread's
- * <tt>ThreadGroup</tt> object is returned, unless this thread
- * has terminated, in which case <tt>null</tt> is returned.
- * @since 1.5
- */
- public UncaughtExceptionHandler getUncaughtExceptionHandler() {
- return uncaughtExceptionHandler != null ?
- uncaughtExceptionHandler : group;
- }
- /**
- * Set the handler invoked when this thread abruptly terminates
- * due to an uncaught exception.
- * <p>A thread can take full control of how it responds to uncaught
- * exceptions by having its uncaught exception handler explicitly set.
- * If no such handler is set then the thread's <tt>ThreadGroup</tt>
- * object acts as its handler.
- * @param eh the object to use as this thread's uncaught exception
- * handler. If <tt>null</tt> then this thread has no explicit handler.
- * @throws SecurityException if the current thread is not allowed to
- * modify this thread.
- * @see #setDefaultUncaughtExceptionHandler
- * @see ThreadGroup#uncaughtException
- * @since 1.5
- */
- public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
- checkAccess();
- uncaughtExceptionHandler = eh;
- }
- /**
- * Dispatch an uncaught exception to the handler. This method is
- * intended to be called only by the JVM.
- */
- private void dispatchUncaughtException(Throwable e) {
- getUncaughtExceptionHandler().uncaughtException(this, e);
- }
- /**
- * Removes from the specified map any keys that have been enqueued
- * on the specified reference queue.
- */
- static void processQueue(ReferenceQueue<Class<?>> queue,
- ConcurrentMap<? extends
- WeakReference<Class<?>>, ?> map)
- {
- Reference<? extends Class<?>> ref;
- while((ref = queue.poll()) != null) {
- map.remove(ref);
- }
- }
- /**
- * Weak key for Class objects.
- **/
- static class WeakClassKey extends WeakReference<Class<?>> {
- /**
- * saved value of the referent's identity hash code, to maintain
- * a consistent hash code after the referent has been cleared
- */
- private final int hash;
- /**
- * Create a new WeakClassKey to the given object, registered
- * with a queue.
- */
- WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) {
- super(cl, refQueue);
- hash = System.identityHashCode(cl);
- }
- /**
- * Returns the identity hash code of the original referent.
- */
- @Override
- public int hashCode() {
- return hash;
- }
- /**
- * Returns true if the given object is this identical
- * WeakClassKey instance, or, if this object's referent has not
- * been cleared, if the given object is another WeakClassKey
- * instance with the identical non-null referent as this one.
- */
- @Override
- public boolean equals(Object obj) {
- if (obj == this)
- return true;
- if (obj instanceof WeakClassKey) {
- Object referent = get();
- return (referent != null) &&
- (referent == ((WeakClassKey) obj).get());
- } else {
- return false;
- }
- }
- }
- /* Some private helper methods */
- private native void setPriority0(int newPriority);
- private native void stop0(Object o);
- private native void suspend0();
- private native void resume0();
- private native void interrupt0();
- }
总结:
实际上,每个thread自带一个ThreadLocalMap,ThreadLocalMap(ThreadLocal t, T firstValue);这个数据结构就存储了每个thread的私有数据,T firstValue是当前线程的私有数据
public T get() {Thread t = Thread.currentThread(); //获得当前线程A
ThreadLocalMap map = getMap(t); //获得当前线程A自带的ThreadLocalMap
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this); //从当前的线程A通过 ThreadLocal 的对象为Key,取出当前线程的私有数据
if (e != null)
return (T)e.value;
}
return setInitialValue();
}