首先看看Thread中定义了哪些常见的变量域:
public class Thread implements Runnable { //Thread实现自Runable
/* Make sure registerNatives is the first thing <clinit> does. */
private static native void registerNatives();
static {
registerNatives();
}
private volatile String name; //线程名
private int priority; //线程优先级
/* Whether or not the thread is a daemon thread. */
private boolean daemon = false; //是否是守护线程
/* What will be run. */
private Runnable target; //线程体Runable
/* The group of this thread */
private ThreadGroup group; //线程组
/* The context ClassLoader for this thread */
private ClassLoader contextClassLoader;
/* 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; //ThreadLocalMap
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null; //可继承的ThreadLocalMap
/*
* 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; //线程栈大小
/*
* Thread ID
*/
private long tid;
/* For generating thread ID */
private static long threadSeqNumber;
/*
* Java thread status for tools, default indicates thread 'not yet started'
*/
private volatile int threadStatus; //线程状态:NEW-0,RUNNABLE,BLOCKED、WAITING、TERMINATED
当我们new Thread(Runable runable)的时候,调用的构造函数是这样的:
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0);
}
public Thread(ThreadGroup group, Runnable target, String name,
long stackSize) {
init(group, target, name, stackSize);
}
可以看到除了传入Runable,我们还可以指定线程所在组、线程栈的大小等,看看init方法里做了什么:
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
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(); //继承父线程的线程组,所以所有启动的线程都是放在同一个线程组main中
}
}
... ...
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.target = target;
setPriority(priority);
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals = //继承父线程的inheritableThreadLocals
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize; //设置线程栈大小
/* Set thread ID */
tid = nextThreadID(); //递增生成线程id
}
private static synchronized long nextThreadID() {
return ++threadSeqNumber;
}
新建了一个线程之后,线程状态是NEW,这时候我们可以调用start启动线程,这时候做了什么:
public synchronized void start() {
if (threadStatus != 0) //只有NEW状态的线程在可以start,不然会抛异常
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 {
... ...
}
}
private native void start0();
如果我们再调用join方法呢:
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
... ...
if (millis == 0) {
while (isAlive()) { //会阻塞其他所有线程直到当前线程执行完毕
wait(0);
}
} else {
while (isAlive()) {
... ...
}
}
}
想要中断线程可以使用interrupt,其他的像stop、destroy方法在最新的jdk中将被废弃移除:
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();
}
但是注意该方法只是设置了中断标志位,并不是直接中止线程,这时有两种情况:1、线程处于阻塞状态,这时会抛出中断异常。2、线程处于非阻塞状态,那JVM会在"合适的时机"终止线程,我们可以在程序中使用while(isInterrupted)来进行判断进而进行相关处理
还有其他的像getStackTrace()获取线程栈信息、yield()让出CPU重新进入就绪状态等
前面提到线程的各个状态,那哪些操作会影响线程的状态呢:
1、start、join、yield等线程自身的方法
2、Object类的wait/notify/notifyAll方法
3、并发库中的工具,如闭锁、栅栏
4、获取锁操作导致的阻塞
... ...
网友评论