六种创建线程的方法
- 实现Runable接口实现run方法
- 继承Thread类重新run方法
- 使用Callable和FutureTask创建线程
- 使用线程池创建线程
- 定时器Timer创建线程
- Spring创建线程
一、Thread和Runnable创建线程的区别和联系
使用Thread方式,我们需要继承Thread类重写run方法,然后调用start方法;使用实现Runable接口的方式,我们需要先创建一个实现了Runable的类,然后创建Thread调用其参数为Ruanable的构造函数,再调用start方法:
Thread thread = new Thread(Runnable r);
其实这两种方式本质上是一样的,我们先看继承创建Thread类的方式:
//1.重写run方法,重写之后这个run方法的逻辑就没有了
@Override
public void run() {
if (target != null) {
target.run();
}
}
//2.调用start方法,start方法转start0方法,shart0是一个native方法,它会调用run方法
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) {
}
}
}
再看实现Runable接口方法,这里不再赘述,直接看使用Thread类参数为Runable的构造函数,这里重点是这个target参数:
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
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) {
if (security != null) {
g = security.getThreadGroup();
}
if (g == null) {
g = parent.getThreadGroup();
}
}
g.checkAccess();
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; //重点语句:target
setPriority(priority);
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
this.stackSize = stackSize;
tid = nextThreadID();
}
我们可以看到,传进来的target参数被设置进入了Thread对象,下一步调用start方法,当调用start方法直到执行run方法,由于我们没有重写Thread的run方法,它是这样的:
@Override
public void run() {
if (target != null) {
target.run();
}
}
它会先判断target是否为空,若不为null则执行target的run方法,而target的run方法就是我们实现Runable接口实现的run方法。
其他的几种方式本质上也是实现/重写run方法,最终还是调用Thread的run方法。所以这就是为什么说只有一种实现线程的方法,那就是实现Thread类。