深入了解Thread常用方法。
这篇博客呢没什么技术含量,本来Thread源码并不在我最近的学习范围内,只是发现线程池的源码看太不懂(毕竟还没怎么用过),所以想着先看看简单点的Thread,在这里呢只列举出了Thread中常用的方法源码。
在正式看源码之前,先来看一段小程序吧
interface MyRunnable{
void run();
}
class MyThread implements MyRunnable{
private MyRunnable target;
@Override
public void run() {
if(target!=null)
target.run();
}
public void start() {
this.run();
}
public MyThread(MyRunnable target) {
this.target=target;
}
}
public class Run implements MyRunnable{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("Run");
}
public static void main(String[] args) {
MyThread myThread=new MyThread(new Run());
myThread.start();
}
}
程序分析:用过Thread就知道,上面这段程序的目的是:模仿Thread调用start()方法。
没错,任何一个Java程序员都会告诉你:创建一个新线程,我们只需要实现Runnable接口,然后实现该接口要求实现的方法run(),最后由Thread实例调用start()方法就可以了。只需要知道在start()方法内部会对run()方法进行调用。事实也是这样。
源码分析
1、start()
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
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 */
}
}
}
源码分析:
当调用start()时,首先会判断threadStatus—线程状态,防止重复启动同一线程
/* * Java thread status for tools, default indicates thread 'not yet started' */ private volatile int threadStatus;
根据源码注释,该值用于记录线程是否已经被启动。0表示没有启动。默认为0。若判断到threadStatus不等于0,则抛出异常IllegalThreadStateException
接下来调用group.add(this);将该线程添加到队列中,group是一个ThreadGroup对象
void add(Thread t) { synchronized (this) { if (destroyed) { throw new IllegalThreadStateException(); } if (threads == null) { threads = new Thread[4]; } else if (nthreads == threads.length) { threads = Arrays.copyOf(threads, nthreads * 2); } threads[nthreads] = t; nthreads++; nUnstartedThreads--; } }
ThreadGroup的本质就是一个数组,用于存放创建好的线程数,该数组的默认大小为4,当线程数超过4时,会调用数组工具类Arrays.copyOf()来为数组扩容,一次性扩大为原来的两倍
接着用变量started来标识线程是否成功创建。调用了start0()来在本地机器中开辟一个线程,若成功创建,则started标识为true,若创建失败,将该线程从数组中移除
private native void start0();
start0()是一个本地方法,在本地机器上开辟了一个新线程的同时会调用run()方法执行对应的工作
2、run()
@Override
public void run() {
if (target != null) {
target.run();
}
}
源码分析:
这个比较简单了,run()方法是在接口Runnable中定义的,Thread实现了Runnable
public class Thread implements Runnable {...}
target是一个Runnable引用,它的值是通过构造方法中传进来的,通过该接口对象调用其实现类的run()方法
public Thread(Runnable target) { this(null, target, "Thread-" + nextThreadNum(), 0); }
3、sleep(),yield()
public static native void sleep(long millis) throws InterruptedException;
public static native void yield();
源码分析:
这两个方法都是本地方法,调用两方法都涉及到一个对象的锁。常常和wait()一起做比较,为了更好的理解,先来看线程的状态有哪些吧。
4、获得线程的状态getState()
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
源码分析:
State是一个枚举,是Thread的内部类,用来表示线程的状态。从源码来看,线程的状态可以分为New(新创建),Runnable(可运行),Block(阻塞),Waiting(等待),Timed Waiting(计时等待),Terminated(被终止)六种
要获得一个线程的状态可以调用getState(),Thread中getState()的实现
public State getState() { // get current thread state return jdk.internal.misc.VM.toThreadState(threadStatus); }
继续深入到jdk.internal.misc.VM.toThreadState(threadStatus);该方法位于VM类
public static Thread.State toThreadState(int threadStatus) { if ((threadStatus & JVMTI_THREAD_STATE_RUNNABLE) != 0) { return RUNNABLE; } else if ((threadStatus & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER) != 0) { return BLOCKED; } else if ((threadStatus & JVMTI_THREAD_STATE_WAITING_INDEFINITELY) != 0) { return WAITING; } else if ((threadStatus & JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT) != 0) { return TIMED_WAITING; } else if ((threadStatus & JVMTI_THREAD_STATE_TERMINATED) != 0) { return TERMINATED; } else if ((threadStatus & JVMTI_THREAD_STATE_ALIVE) == 0) { return NEW; } else { return RUNNABLE; } }
6、最后再来说说sleep(),yield(),wait()
- sleep()和yield()都是Thread中的方法
- wait()是Object中的方法
- 通过调用sleep(milliseconds)可以使任务进入休眠状态,在这种情况下,任务在指定的时间内不会运行
- 通过调用yield()可以告诉线程调用机制,自己已经完成了最重要的任务,接下来可以把CPU时间片段分配给其他线程了
- 通过调用wait()可以使线程挂起。直到线程得到了notify()或notifyAll()消息,线程才进入就绪状态
- 调用sleep()的时候,对象的锁并没有被释放,yield()也属于这种情况,意味着其他线程仍然不能获得这个锁
- 调用wait()的时候,对象的锁会被释放,意味着另一个线程可以获得这个锁
关于sleep(),yield(),wait()与线程状态以及锁的关系,用一张图表示
图中对应了线程的六种状态,其中就绪和运行都属于Runnable状态(Java的规范说明没有将Runnable作为一个单独的状态,一个正在运行的线程仍然处于可运行状态)