本节摘要:分析Thread类的几个核心方法,对比start()和run()方法的区别
一、 源码解析
1.1、构造函数
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
Thread(Runnable target, AccessControlContext acc) {
init(null, target, "Thread-" + nextThreadNum(), 0, acc);
}
public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0);
}
public Thread(String name) {
init(null, null, name, 0);
}
public Thread(ThreadGroup group, String name) {
init(group, null, name, 0);
}
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);
}
public Thread(ThreadGroup group, Runnable target, String name,
long stackSize) {
init(group, target, name, stackSize);
}
1.2 参数说明
target:一个Runnable对象,线程启动后,会调用它的run()方法
name:线程名字
group:线程所属分组,如果没有指定,线程被归入到该线程的父线程的线程组中
stackSize:线程堆栈大小
AccessControlContext :设置访问权限控制环境
1.3 常用方法
public void start();//启动一个新线程,该方法将立即返回,新线程将运行
public void run();//覆盖该方法,添加线程具体执行内容
public static void sleep(long millis) throws InterruptedException;//使当前正在执行的线程睡眠指定的时间
public void interrupt();//用于将一个中断请求发送给线程
public static boolean interrupted();//用于测试当前线程(即正在执行该指令的线程)是否已经被中断
public boolean isInterrupted();//用于测试某个线程是否已经被中断
public final boolean isAlive();//用于测试某个线程是否还活着
public final void setPriority(int newPriority);//设置线程的优先级
1.4 关键方法分析
- init()方法:Thread构造器都会调用init()方法,它的作用是初始化一个Thread,接下来我们看看init方法具体做了什么
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
//线程名字不能为空,否则抛NPE
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
//获得父线程,即当前线程,此时新的线程还没有被创建,currentThread()是本地方法
Thread parent = currentThread();
//获取系统的安全管理器,安全管理器是一个允许应用程序实现安全策略的类
SecurityManager security = System.getSecurityManager();
//线程组为空
if (g == null) {
/* If there is a security manager, ask the security manager what to do. */
if (security != null) {
g = security.getThreadGroup();
}
//如果没有指定线程组,则获取父线程的线程组
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);
}
}
//将线程组中就绪的线程数加1
g.addUnstarted();
this.group = g;
this.daemon = parent.isDaemon();//根据父线程是否为守护线程来设置线程实例是否为守护线程
this.priority = parent.getPriority();//获取父线程的线程优先级
//设置classLoader
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;//线程实例,就是构造器传进来的Runnable,线程执行就是执行该实例的run方法
setPriority(priority);//设置线程优先级
//将父线程的ThreadLocaleMap变量信息拷贝到当前线程实例
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();//线程ID
}
- start()方法:线程调用start方法,就进入到Runnable状态,看看start()里都做了什么
//这是一个同步方法
public synchronized void start() {
//状态为0代表状态为new,只有状态为new的线程才能调用start(),下面的逻辑表明start方法只能被执行一次
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
start0();//启动线程,是一个本地方法,c语言实现
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 */
}
}
}
- run方法
@Override
public void run() {
//target是一个Runnable的实例,新创建的线程实际运行这个Runnable实例的run方法,因此需要重写该方法
if (target != null) {
target.run();
}
}
二、示例
public class MyThread extends Thread {
public static void main(String[] args) {
// System.out.println("主线程名字:" + Thread.currentThread().getName());
// System.out.println(Thread.currentThread().getThreadGroup().getName());
Thread thread = new MyThread("myThread");
thread.run();//直接调用run方法
thread.start();//新启动一个线程
}
public MyThread(String name) {
super(name);
}
@Override
public void run() {
System.out.println("线程名字:" + Thread.currentThread().getName());
// System.out.println(Thread.currentThread().getThreadGroup().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出结果:
线程名字:main
线程名字:myThread
三、总结
程序从main方法开始,首先创建了一个线程实例,然后直接调用run方法,此时并没有开启新的线程,而是在"主线程"中直接运行的run方法,因此线程名是main,紧接着程序调用start()方法,jvm开启一个新的线程,并执行新线程的run方法,此时线程名为"myThread"。
因此:
start():启动一个线程,新线程会执行run()方法
run(): 和普通方法没有区别,如果单独调用run()方法,会在当前线程执行run方法**
转载请注明作者及出处,并附上链接http://www.jianshu.com/u/ada8c4ee308b