Thread就是程序中一个线程的执行.JVM允许一个应用中多个线程并发执行
每个线程都有优先级.高优先级线程优先于低优先级线程执行 每个线程都可以(不可以)被标记为守护线程 当线程中的run()方法代码里面又创建了一个新的线程对象时,新创建的线程优先级和父线程优先级一样 当且仅当父线程为守护线程时,新创建的线程才会是守护线程
当JVM启动时,通常会有唯一的一个非守护线程(这一线程用于调用指定类的main()方法) JVM会持续执行线程直到下面某一个情况发生为止: 1.类运行时exit()方法被调用且安全机制允许此exit()方法的调用. 2.所有非守护类型的线程均已经终止,或者run()方法调用返回或者在run()方法外部抛出了一些可传播性的异常.
public
class Thread implements Runnable
/* Make sure registerNatives is the first thing does. */
//注册本地方法
private static native void registerNatives();
static {
registerNatives();
}
//线程名
private volatile String name;
//优先级
private int priority;
//内置的Thread类
private Thread threadQ;
//JVM中的java thread 指针
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 */
//jvm 状态
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. */
//与当前线程绑定的 ThreadLocalMap
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
//继承的 ThreadLocalMap
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
*/
//此线程的 ID
private long tid;
/* For generating thread ID */
//线程名称序列 ID
private static long threadSeqNumber;
/* Java thread status for tools,
* initialized to indicate thread 'not yet started'
*/
//此线程的状态 Thread类定义了6个线程状态:New、Runnable、Blocked、Waiting、TimedWaiting、Terminated(终止)
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
* 当前线程在此目标对象 parkBlocker 上阻塞
* java.util.concurrent.locks.LockSupport.park.
*/
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.
* 阻塞此线程的可中断 IO 对象
*/
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;
private static final StackTraceElement[] EMPTY_STACK_TRACE
= new StackTraceElement[0];
private static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION =
new RuntimePermission("enableContextClassLoaderOverride");
// null unless explicitly set
private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
// null unless explicitly set
private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
// The following three initially uninitialized fields are exclusively
// managed by class java.util.concurrent.ThreadLocalRandom. These
// fields are used to build the high-performance PRNGs in the
// concurrent code, and we can not risk accidental false sharing.
// Hence, the fields are isolated with @Contended.
/** The current seed for a ThreadLocalRandom */
@sun.misc.Contended("tlr")
long threadLocalRandomSeed;
/** Probe hash value; nonzero if threadLocalRandomSeed initialized */
@sun.misc.Contended("tlr")
int threadLocalRandomProbe;
/** Secondary seed isolated from public ThreadLocalRandom sequence */
@sun.misc.Contended("tlr")
int threadLocalRandomSecondarySeed;
/* 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();
private native void setNativeName(String name);
构造方法
/**
* 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-"+}n, where n 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-"+}n, where n 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);
}
/**
* Creates a new Thread that inherits the given AccessControlContext.
* This is not a public constructor.
*/
Thread(Runnable target, AccessControlContext acc) {
init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
}
/**
* 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-"+}n, where n 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}.
*
* If there is a security manager, its
* {@link SecurityManager#checkAccess(ThreadGroup) checkAccess}
* method is invoked with the ThreadGroup as its argument.
*
*
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.
*
*
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.
*
*
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 stack size.
*
*
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. The effect of the
* {@code stackSize} parameter, if any, is highly platform dependent.
*
*
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 StackOverflowError}.
* 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 stackSize parameter
* and the maximum recursion depth and concurrency level are
* platform-dependent. On some platforms, the value of the
* {@code stackSize} parameter may have no effect whatsoever.
*
*
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).
*
*
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.
*
*
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.
*
*
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);
}
/**
* Initializes a Thread with the current AccessControlContext.
* @see #init(ThreadGroup,Runnable,String,long,AccessControlContext,boolean)
*/
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
/**
* 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.
* @param acc the AccessControlContext to inherit, or
* AccessController.getContext() if null
* @param inheritThreadLocals if {@code true}, inherit initial values for
* inheritable thread-locals from the constructing thread
* 初始化线程
*/
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
// 参数校验,线程name不能为null
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
// 当前线程就是该线程的父线程
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();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
if (inheritThreadLocals && 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 */
// 分配线程id
tid = nextThreadID();
}
内部类
UncaughtExceptionHandler
未捕获异常处理器,在线程由于未捕获的异常终止时,JVM会进行一些处理,处理流程如下:
- JVM调用终止线程的getUncaughtExceptionHandler方法获取终止线程的uncaughtExceptionHandler
- 非null则调用uncaughtExceptionHandler的uncaughtException方法,同时将此终止线程和其异常作为参数传入
- null则找到终止线程所在的最上级线程组,调用其uncaughtException方法,同时将此终止线程和其异常作为参数传入
- 调用Thread.getDefaultUncaughtExceptionHandler获取handle,非空则调用其uncaughtException方法,空则判断调用e.printStackTrace(System.err)处理
/**
* Interface for handlers invoked when a Thread abruptly
* terminates due to an uncaught exception.
* When a thread is about to terminate due to an uncaught exception
* the Java Virtual Machine will query the thread for its
* UncaughtExceptionHandler using
* {@link #getUncaughtExceptionHandler} and will invoke the handler's
* uncaughtException method, passing the thread and the
* exception as arguments.
* If a thread has not had its UncaughtExceptionHandler
* explicitly set, then its ThreadGroup object acts as its
* UncaughtExceptionHandler. If the ThreadGroup 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
* 内部异常处理接口
*/
@FunctionalInterface
public interface UncaughtExceptionHandler {
/**
* Method invoked when the given thread terminates due to the
* given uncaught exception.
*
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);
}
/**
* 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
* ThreadGroup object is returned, unless this thread
* has terminated, in which case null is returned.
* @since 1.5
* @return the uncaught exception handler for this thread
*/
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
//返回handle本身或线程组
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
Caches&WeakClassKey
我们可以看到WeakClassKey这个内部类继承了WeakReference,而WeakClassKey被Caches所使用,从名字我们也能明白其部分含义,本地缓存,WeakClassKey是弱引用相关类. subclassAudits提供了一个哈希表缓存,该缓存的键类型为java.lang.Thread.WeakClassKey,注意看它的值类型是一个java.lang.Boolean类型的,从其代码注释可以知道这个哈希表缓存中保存的是所有子类的代码执行安全性检测结果 subclassAuditsQueue定义了一个Queue队列,保存已经审核过的子类弱引用
/** cache of subclass security audit results */
/* Replace with ConcurrentReferenceHashMap when/if it appears in a future
* release */
//Caches缓存了子类安全检查结果。如果未来要进行使用,采用ConcurrentReferenceHashMap替换。
private static class Caches {
/** cache of subclass security audit results */
//缓存安全检查结果
static final ConcurrentMap subclassAudits =
new ConcurrentHashMap();
/** queue for WeakReferences to audited subclasses */
//队列
static final ReferenceQueue subclassAuditsQueue =
new ReferenceQueue();
}
/**
* Weak key for Class objects.
**/
static class WeakClassKey extends WeakReference {
/**
* 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 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;
}
}
}
/**
* 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);
// 生成key
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();
}
State
/**
* A thread state. A thread can be in one of the following states:
*
* - {@link #NEW}
* A thread that has not yet started is in this state.
*
* - {@link #RUNNABLE}
* A thread executing in the Java virtual machine is in this state.
*
* - {@link #BLOCKED}
* A thread that is blocked waiting for a monitor lock
* is in this state.
*
* - {@link #WAITING}
* A thread that is waiting indefinitely for another thread to
* perform a particular action is in this state.
*
* - {@link #TIMED_WAITING}
* A thread that is waiting for another thread to perform an action
* for up to a specified waiting time is in this state.
*
* - {@link #TERMINATED}
* A thread that has exited is in this state.
*
*
*
*
* 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
* Java语言使用Thread类及其子类的对象来表示线程,在它的一个完整的声明周期通常要经历以下状态
*/
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:
*
* - {@link Object#wait() Object.wait} with no timeout
* - {@link #join() Thread.join} with no timeout
* - {@link LockSupport#park() LockSupport.park}
*
*
* A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called Object.wait()
* on an object is waiting for another thread to call
* Object.notify() or Object.notifyAll() on
* that object. A thread that has called Thread.join()
* 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:
*
* - {@link #sleep Thread.sleep}
* - {@link Object#wait(long) Object.wait} with timeout
* - {@link #join(long) Thread.join} with timeout
* - {@link LockSupport#parkNanos LockSupport.parkNanos}
* - {@link LockSupport#parkUntil LockSupport.parkUntil}
*
* 超时等待态
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
* 死亡 终止态
*/
TERMINATED;
}
初始态(NEW):
- 创建一个Thread对象,但还未调用start()启动线程时,线程处于初始态
运行态(RUNNABLE):
运行态在Java中包括就绪态和运行态
1.就绪态:
- 该状态下的线程已经获得执行所需的所有资源,只要CPU分配执行权就能运行
- 所有就绪态的线程存放在就绪队列中
2.运行态:
- 获得CPU执行权,正在执行的线程
- 由于一个CPU同一时刻只能执行一条线程,因此每个CPU每个时刻只有一个运行态的线程
阻塞态(BLOCKED)
- 当一条正在执行的线程请求某一资源失败时,就会进入阻塞态
- 而在Java中,阻塞态专指请求锁失败时进入的状态
- 由一个阻塞队列存放所有阻塞态的线程。处于阻塞态的线程会不断请求资源,一旦请求成功,就会进入就绪队列,等待执行
等待态(WAITING)
- 当前线程中调用wait、join、park函数时,当前线程就会进入等待态
- 也有一个等待队列存放所有等待态的线程
- 线程处于等待态表示它需要等待其他线程的指示才能继续运行
- 进入等待态的线程会释放CPU执行权,并释放资源(如:锁)
超时等待态(TIMED_WAITING)
- 当运行中的线程调用sleep(time)、wait、join、parkNanos、parkUntil时,就会进入该状态
- 它和等待态一样,并不是因为请求不到资源,而是主动进入,并且进入后被其他线程唤醒或超时自动唤醒
- 进入该状态后释放CPU执行权和占有的资源,其中wait()方法会释放CPU执行权和占有的锁,sleep(long)方法仅释放CPU使用权,锁仍然占用
- 与等待态的区别:到了超时时间后自动进入阻塞队列,开始竞争锁
终止态(TERMINATED)
- 线程执行结束后的状态
其中有几点需要注意的:
- yield方法仅释放CPU执行权,锁仍然占用,线程会被放入就绪队列,会在短时间内再次执行
- wait和notify必须配套使用,即必须使用同一把锁调用
- wait和notify必须放在一个同步块中调用,wait和notify的对象必须是他们所处同步块的锁对象
/**
* Causes this thread to begin execution; the Java Virtual Machine
* calls the run
method of this thread.
*
* The result is that two threads are running concurrently: the
* current thread (which returns from the call to the
* start
method) and the other thread (which executes its
* run
method).
*
* 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".
*/
//假若当前线程初始化还未做好,不能start,0->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该线程即将启动,group的未启动线程数量减1
group.add(this);
boolean started = false;
try {
// 调用native的start0()方法 启动线程,启动后执行run()方法
start0();
started = true;
} finally {
try {
//启动不成功,group设置当前线程启动失败
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();
interrupt
/**
* Interrupts this thread.
*
* 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.
*
*
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}.
*
*
If this thread is blocked in an I/O operation upon an {@link
* java.nio.channels.InterruptibleChannel InterruptibleChannel}
* 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}.
*
*
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.
*
*
If none of the previous conditions hold then this thread's interrupt
* status will be set.
*
* 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
* 请求终止线程。interrupt不会真正停止一个线程,它仅仅是给这个线程发了一个信号,
* 告诉它要结束了,具体要中断还是继续运行,将由被通知的线程自己处理
*/
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();
}
join
/**
* Waits at most {@code millis} milliseconds for this thread to
* die. A timeout of {@code 0} means to wait forever.
*
* 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
* interrupted status of the current thread is
* cleared when this exception is thrown.
* 实际上是利用 wait/notify机制 来实现的
*/
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis osthread() != NULL) {
// Note: the current thread is not being used within "prepare".
// 准备Java本地线程,链接Java线程 C++线程
native_thread->prepare(jthread);
}
}
}
if (throw_illegal_thread_state) {
THROW(vmSymbols::java_lang_IllegalThreadStateException());
}
assert(native_thread != NULL, "Starting null thread?");
if (native_thread->osthread() == NULL) {
// No one should hold a reference to the 'native_thread'.
delete native_thread;
if (JvmtiExport::should_post_resource_exhausted()) {
JvmtiExport::post_resource_exhausted(
JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_THREADS,
"unable to create new native thread");
}
THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),
"unable to create new native thread");
}
// 启动Java本地线程
Thread::start(native_thread);//启动javaThread
JVM_END
这里分为两个步骤:
查看thread.cpp,可以看到JavaThread的构造函数,其中创建了一个本地线程:
- 创建线程:
new JavaThread(&thread_entry, sz)
启动创建的线程
- 启动线程:
Thread::start(native_thread);
new JavaThread(&thread_entry, sz)
thread.cpp
找到JavaThread类构造方法
JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) :
Thread()
#if INCLUDE_ALL_GCS
, _satb_mark_queue(&_satb_mark_queue_set),
_dirty_card_queue(&_dirty_card_queue_set)
#endif // INCLUDE_ALL_GCS
{
if (TraceThreadEvents) {
tty->print_cr("creating thread %p", this);
}
initialize();// 初始化实例变量
_jni_attach_state = _not_attaching_via_jni;
set_entry_point(entry_point);//entry_point 设置Java执行线程入口,最终会调用
// Create the native thread itself.
// %note runtime_23
// 创建系统级本地线程
os::ThreadType thr_type = os::java_thread;
thr_type = entry_point == &compiler_thread_entry ? os::compiler_thread :
os::java_thread;
os::create_thread(this, thr_type, stack_sz);// 调用系统库创建底层线程
_safepoint_visible = false;
// The _osthread may be NULL here because we ran out of memory (too many threads active).
// We need to throw and OutOfMemoryError - however we cannot do this here because the caller
// may hold a lock and all locks must be unlocked before throwing the exception (throwing
// the exception consists of creating the exception object & initializing it, initialization
// will leave the VM via a JavaCall and then all locks must be unlocked).
//
// The thread is still suspended when we reach here. Thread must be explicit started
// by creator! Furthermore, the thread must also explicitly be added to the Threads list
// by calling Threads:add. The reason why this is not done here, is because the thread
// object must be fully initialized (take a look at JVM_Start)
}
创建内核线程
创建内核线程:os::create_thread(this, thr_type, stack_sz);
os为操作系统
我们能在hotspot源码目录的src/os下找到不同系统的方法,我们以linux系统为例。
查看os_linux.cpp,找到create_thread方法:
找到os_linux.cpp
bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
assert(thread->osthread() == NULL, "caller responsible");
// Allocate the OSThread object
OSThread* osthread = new OSThread(NULL, NULL);// 创建操作系统线程
if (osthread == NULL) {
return false;
}
// set the correct thread state
osthread->set_thread_type(thr_type);
// Initial state is ALLOCATED but not INITIALIZED
osthread->set_state(ALLOCATED);// 把osthread状态设置为已分配
thread->set_osthread(osthread);// 绑定至JavaThread
// init thread attributes
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// stack size
// 初始化线程数
if (os::Linux::supports_variable_stack_size()) {
// calculate stack size if it's not specified by caller
if (stack_size == 0) {
stack_size = os::Linux::default_stack_size(thr_type);
switch (thr_type) {
case os::java_thread:
// Java threads use ThreadStackSize which default value can be
// changed with the flag -Xss
assert (JavaThread::stack_size_at_create() > 0, "this should be set");
stack_size = JavaThread::stack_size_at_create();
break;
case os::compiler_thread:
if (CompilerThreadStackSize > 0) {
stack_size = (size_t)(CompilerThreadStackSize * K);
break;
} // else fall through:
// use VMThreadStackSize if CompilerThreadStackSize is not defined
case os::vm_thread:
case os::pgc_thread:
case os::cgc_thread:
case os::watcher_thread:
if (VMThreadStackSize > 0) stack_size = (size_t)(VMThreadStackSize * K);
break;
}
}
stack_size = MAX2(stack_size, os::Linux::min_stack_allowed);
pthread_attr_setstacksize(&attr, stack_size);
} else {
// let pthread_create() pick the default value.
}
// glibc guard page
pthread_attr_setguardsize(&attr, os::Linux::default_guard_size(thr_type));
ThreadState state;
{
// Serialize thread creation if we are running with fixed stack LinuxThreads
bool lock = os::Linux::is_LinuxThreads() && !os::Linux::is_floating_stack();
if (lock) {
os::Linux::createThread_lock()->lock_without_safepoint_check();
}
pthread_t tid;
// 调用系统库创建线程,thread_native_entry为本地Java线程执行入口
int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);//创建linux线程
pthread_attr_destroy(&attr);
if (ret != 0) {
if (PrintMiscellaneous && (Verbose || WizardMode)) {
perror("pthread_create()");
}
// Need to clean up stuff we've allocated so far
thread->set_osthread(NULL);
delete osthread;
if (lock) os::Linux::createThread_lock()->unlock();
return false;
}
// Store pthread info into the OSThread
osthread->set_pthread_id(tid);
// Wait until child thread is either initialized or aborted
{
Monitor* sync_with_child = osthread->startThread_lock();
MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
while ((state = osthread->get_state()) == ALLOCATED) {//等待创建完成
sync_with_child->wait(Mutex::_no_safepoint_check_flag);
}
}
if (lock) {
os::Linux::createThread_lock()->unlock();
}
}
// Aborted due to thread limit being reached
if (state == ZOMBIE) {//创建失败
thread->set_osthread(NULL);
delete osthread;
return false;
}
// The thread is returned suspended (in state INITIALIZED),
// and is started higher up in the call chain
assert(state == INITIALIZED, "race condition");
return true;
}
这个pthread_create方法就是最终创建系统线程的底层方法
因此java线程start方法的本质其实就是通过jni机制,最终调用系统底层的pthread_create方法,创建了一个系统线程,因此java线程和系统线程是一个一对一的关系
pthread_create到这里我们的探究并没有结束,在java的Thread类中,我们会传入一个执行我们指定任务的Runnable对象,在Thread的run()方法中调用。当java通过jni调用到pthread_create创建完系统线程后,又要如何回调java中的run方法呢?
前面的探究我们是从java层开始,从上往下找,此时我们要反过来,从下往上找了。
int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);
1)pthread_create
pthread_create是UNIX环境创建线程函数
头文件
#include
函数声明
int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict_attr,void*(*start_rtn)(void*),void *restrict arg);
返回值
若成功则返回0,否则返回出错编号
参数
第一个参数为指向线程标识符的指针。
第二个参数用来设置线程属性。
第三个参数是线程运行函数的起始地址。
最后一个参数是运行函数的参数。
另外
pthread并非Linux系统的默认库
查看create_thread方法中调用pthread_create的代码,可以看到java_start就是系统线程所执行的方法,而thread则是传递给java_start的参数:
int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);
查看java_start()方法,它获取的参数正是一个Thread,并调用其run()方法。注意这个Thread是C++级别的线程,来自于pthread_create方法的第4个参数:
os_linux.cpp
// 线程执行入口
// Thread start routine for all newly created threads
static void *java_start(Thread *thread) {
// Try to randomize the cache line index of hot stack frames.
// This helps when threads of the same stack traces evict each other's
// cache lines. The threads can be either from the same JVM instance, or
// from different JVM instances. The benefit is especially true for
// processors with hyperthreading technology.
static int counter = 0;
int pid = os::current_process_id();
alloca(((pid ^ counter++) & 7) * 128);
ThreadLocalStorage::set_thread(thread);
OSThread* osthread = thread->osthread();
// 获取同步锁
Monitor* sync = osthread->startThread_lock();
// non floating stack LinuxThreads needs extra check, see above
if (!_thread_safety_check(thread)) {
// notify parent thread
MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
osthread->set_state(ZOMBIE);
sync->notify_all();
return NULL;
}
// thread_id is kernel thread id (similar to Solaris LWP id)
osthread->set_thread_id(os::Linux::gettid());
if (UseNUMA) {
int lgrp_id = os::numa_get_group_id();
if (lgrp_id != -1) {
thread->set_lgrp_id(lgrp_id);
}
}
// initialize signal mask for this thread
os::Linux::hotspot_sigmask(thread);
// initialize floating point control register
os::Linux::init_thread_fpu_state();
// handshaking with parent thread
{
MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
// notify parent thread
osthread->set_state(INITIALIZED);
sync->notify_all();
// wait until os::start_thread()
// 等待调用os::start_thread(),然后继续执行*******
while (osthread->get_state() == INITIALIZED) {
sync->wait(Mutex::_no_safepoint_check_flag);
}
}
// call one more level start routine
// 调用JavaThread的run方法以便触发执行java.lang.Thread.run()
thread->run();
return 0;
}
初始化工作完成之后当前线程wait,等待调用Thread::start(native_thread);唤醒
// wait until os::start_thread()
// 等待调用os::start_thread(),然后继续执行*******
while (osthread->get_state() == INITIALIZED) {
sync->wait(Mutex::_no_safepoint_check_flag);
}
启动线程
Thread::start(native_thread);
thread.cpp
void Thread::start(Thread* thread) {
trace("start", thread);
// Start is different from resume in that its safety is guaranteed by context or
// being called from a Java method synchronized on the Thread object.
if (!DisableStartThread) {
if (thread->is_Java_thread()) {
// Initialize the thread state to RUNNABLE before starting this thread.
// Can not set it after the thread started because we do not know the
// exact thread state at that time. It could be in MONITOR_WAIT or
// in SLEEPING or some other state.
// 设置线程状态为RUNNABLE
java_lang_Thread::set_thread_status(((JavaThread*)thread)->threadObj(),
java_lang_Thread::RUNNABLE);
}
// 启动本地线程
os::start_thread(thread);
}
}
在启动该线程之前,将线程状态初始化为 RUNNABLE。
不能在线程启动后设置,因为我们不知道 正确的线程状态,它可能在 MONITOR_WAIT 或 在睡眠或其他状态
启动内核线程os.cpp
void os::start_thread(Thread* thread) {
// guard suspend/resume
MutexLockerEx ml(thread->SR_lock(), Mutex::_no_safepoint_check_flag);
OSThread* osthread = thread->osthread();
// osthread状态设为运行中
osthread->set_state(RUNNABLE);
// 最终启动线程
pd_start_thread(thread);
}
os_linux.cpp
通知子线程JavaThread继续往下执行
void os::pd_start_thread(Thread* thread) {
OSThread * osthread = thread->osthread();
assert(osthread->get_state() != INITIALIZED, "just checking");
Monitor* sync_with_child = osthread->startThread_lock();
MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
// 通知子线程继续往下执行
sync_with_child->notify();
}
全局函数notify
bool Monitor::notify() {
assert (_owner == Thread::current(), "invariant") ;
assert (ILocked(), "invariant") ;
if (_WaitSet == NULL) return true ;
NotifyCount ++ ;
// Transfer one thread from the WaitSet to the EntryList or cxq.
// Currently we just unlink the head of the WaitSet and prepend to the cxq.
// And of course we could just unlink it and unpark it, too, but
// in that case it'd likely impale itself on the reentry.
Thread::muxAcquire (_WaitLock, "notify:WaitLock") ;
ParkEvent * nfy = _WaitSet ;
if (nfy != NULL) { // DCL idiom
_WaitSet = nfy->ListNext ;
assert (nfy->Notified == 0, "invariant") ;
// push nfy onto the cxq
for (;;) {
const intptr_t v = _LockWord.FullWord ;
assert ((v & 0xFF) == _LBIT, "invariant") ;
nfy->ListNext = (ParkEvent *)(v & ~_LBIT);
if (CASPTR (&_LockWord, v, UNS(nfy)|_LBIT) == v) break;
// interference - _LockWord changed -- just retry
}
// Note that setting Notified before pushing nfy onto the cxq is
// also legal and safe, but the safety properties are much more
// subtle, so for the sake of code stewardship ...
OrderAccess::fence() ;
nfy->Notified = 1;
}
Thread::muxRelease (_WaitLock) ;
if (nfy != NULL && (NativeMonitorFlags & 16)) {
// Experimental code ... light up the wakee in the hope that this thread (the owner)
// will drop the lock just about the time the wakee comes ONPROC.
nfy->unpark() ;
}
assert (ILocked(), "invariant") ;
return true ;
}
这个代码中看到这段注释,这里提到 WaitSet , EntryList,cxq 这是 隐式锁 [[Synchronized 内部的实现原理呀]] 或者 称它为 [[Monitor机制]]
WaitSet: 是一个等待队列,存放进入等待状态的线程 cxq: 是一个竞争队列,所有请求锁🔒的线程会先到这里 EntryList: 存放 cxq 中有资格成为候选资源去竞争锁的线程
运行线程thread.cpp
查看JavaThread::run()方法,其主要的执行内容在thread_main_inner方法中:
void JavaThread::run() {
// 执行run方法前的初始化和缓存工作
this->initialize_tlab();
...
// 通知JVMTI
if (JvmtiExport::should_post_thread_life()) {
JvmtiExport::post_thread_start(this);
}
EventThreadStart event;
if (event.should_commit()) {
event.set_thread(THREAD_TRACE_ID(this));
event.commit();
}
// ==================================================
// 执行Java级别Thread类run()方法内容
// ==================================================
thread_main_inner();
}
查看JavaThread::thread_main_inner()方法,其内部通过entry_point执行回调:
thread.cpp
void JavaThread::thread_main_inner() {
if (!this->has_pending_exception() &&
!java_lang_Thread::is_stillborn(this->threadObj())) {
{
ResourceMark rm(this);
this->set_native_thread_name(this->get_thread_name());
}
HandleMark hm(this);
// ==========================================
// 执行线程入口java.lang.Thread # run()方法
// ==========================================
//调用entry_point,执行外部传入的方法,注意这里的第一个参数this
//即JavaThread对象本身,后面会看到该方法的定义
this->entry_point()(this, this);
}
DTRACE_THREAD_PROBE(stop, this);
// 退出并释放空间
this->exit(false);
// 释放资源
delete this;
}
entry_point
查看JavaThread::JavaThread构造函数,可以看到这里的entry_point是从外部传入的
thread.cpp
JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) :
Thread()
#if INCLUDE_ALL_GCS
, _satb_mark_queue(&_satb_mark_queue_set),
_dirty_card_queue(&_dirty_card_queue_set)
#endif // INCLUDE_ALL_GCS
{
if (TraceThreadEvents) {
tty->print_cr("creating thread %p", this);
}
initialize();
_jni_attach_state = _not_attaching_via_jni;
set_entry_point(entry_point);
// Create the native thread itself.
// %note runtime_23
os::ThreadType thr_type = os::java_thread;
thr_type = entry_point == &compiler_thread_entry ? os::compiler_thread :
os::java_thread;
os::create_thread(this, thr_type, stack_sz);
_safepoint_visible = false;
// The _osthread may be NULL here because we ran out of memory (too many threads active).
// We need to throw and OutOfMemoryError - however we cannot do this here because the caller
// may hold a lock and all locks must be unlocked before throwing the exception (throwing
// the exception consists of creating the exception object & initializing it, initialization
// will leave the VM via a JavaCall and then all locks must be unlocked).
//
// The thread is still suspended when we reach here. Thread must be explicit started
// by creator! Furthermore, the thread must also explicitly be added to the Threads list
// by calling Threads:add. The reason why this is not done here, is because the thread
// object must be fully initialized (take a look at JVM_Start)
}
jvm.cpp
查看JVM_StartThread方法,可以看到传给JavaThread的entry_point是thread_entry
JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
JVMWrapper("JVM_StartThread");
JavaThread *native_thread = NULL;
bool throw_illegal_thread_state = false;
{
...
/**
* 传给构造函数的entry_point是thread_entry
*/
native_thread = new JavaThread(&thread_entry, sz);
...
}
...
JVM_END
查看thread_entry,其中调用了JavaCalls::call_virtual去回调java级别的方法,其实看到它的方法签名就能猜到个大概了
jvm.cpp
static void thread_entry(JavaThread* thread, TRAPS) {
HandleMark hm(THREAD);
/**
* obj正是根据thread对象获取到的,JavaThread在调用时会传入this
*/
Handle obj(THREAD, thread->threadObj());
/**
* 返回结果是void
*/
JavaValue result(T_VOID);
/**
* 回调java级别的方法
*/
JavaCalls::call_virtual(&result,//返回对象
//实例对象
obj,
//类
KlassHandle(THREAD, SystemDictionary::Thread_klass()),
//方法名
vmSymbols::run_method_name(),
//方法签名
vmSymbols::void_method_signature(),
THREAD);
最终执行实例化JavaThread时设置的入口方法entry_point,代表了Java代码级别Java线程执行入口, 这里通过JavaCalls组件调用java.lang.Thread.run()
方法,执行真正的用户逻辑代码。
vmSymbols.hpp
我们查看获取方法名run_method_name和方法签名void_method_signature的部分,可以看到正是获取一个方法名为run,且不获取任何参数,返回值为void的方法:
template(run_method_name, "run")
...
template(void_method_signature, "()V")
于是系统线程就能成功地回调java级别的run方法了!
@Override
public void run() {
if (target != null) {
target.run();
}
}
方法一回调直接使用Thread的run方法
Thread t1 = new Thread("t1") {
@Override
// run 方法内实现了要执行的任务
public void run() {
System.out.println(Thread.currentThread().getName()+" run");
}
};
t1.start();
在执行run方法时
Thread.java
@Override
public void run() {
if (target != null) {//null
target.run();
}
}
调用重写Thread的run方法
方法二回调使用Runable的run方法 Runnable task = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" run");
}
};
// 参数1 是任务对象; 参数2 是线程名字,推荐
Thread t1 = new Thread(task, "t1");
t1.start();
Runnable 对象赋值给Thread类的target
Thread类run()判断target != null
执行target.run();采用Runnable 的run方法
@Override
public void run() {
if (target != null) {//task
target.run();
}
}
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface Runnable
is used
* to create a thread, starting the thread causes the object's
* run
method to be called in that separately executing
* thread.
*
* The general contract of the method run
is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
最终重写的是Runnable 的run方法
总结两种方法都执行到thread类的run方法
@Override
public void run() {
if (target != null) {
target.run();
}
}
判断target是否为null,如果为null就重写Thread 类的run方法(方法一)
如果不为null,就重写Runnable 的run方法(方法二)
方法1 是把线程和任务合并在了一起,方法2 是把线程和任务分开了 用 Runnable 更容易与线程池等高级 API 配合 用 Runnable 让任务类脱离了 Thread 继承体系,更灵活
参考
深入Java Thread底层实现