1、通过Thread创建线程
// 直接使用Thread类
Thread t1 = new Thread(){
@Override
public void run(){
log.debug("hello");
}
};
t1.start();
- 通过构造方法创建线程
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
- 调用init()方法进行初始化
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
- 继续init()方法套娃,初始化线程组、是否为守护线程、target这些属性
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
// 如果没有自定义name,会调用nextThreadNum()为线程生成名称
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();
// 赋值target属性
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 */
tid = nextThreadID();
}
- 调用start()方法启动线程
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".
*/
// threadstatus=0对应着线程的NEW状态,如果不是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.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 */
}
}
}
- 调用start0()方法
private native void start0();
这是一个native方法,就是把线程的创建交给操作系统去完成了。
- 调用run()方法 run()方法是任务的执行体,一般把需要执行的任务内容通过重写run()方法去实现
@Override
public void run() {
if (target != null) {
target.run();
}
}
在这里可以看到,如果有传入一个Runnable对象,就会调用Runnable的run()方法,否则就执行Thread类自身的run()方法。 至此,一个线程的创建和启动就完成了。
2、通过Runnable+Thread创建线程
Runnable runnable = new Runnable() {
@Override
public void run() {
log.debug("t2 running..");
}
};
Thread t = new Thread(runnable);
t.start();
流程跟通过Thread创建线程一样,但是有两点不同
- 通过Runnable+Thread创建线程,把任务和线程分开了,也就是Thread负责创建线程,任务的执行交给Runable
- 由于Thread的构造方法传入了Runnable作为target,所以会执行target的run()方法,而不是Thread本身的run()方法
使用Runnable创建线程的好处?
用Runnable更容易与线程池等高级API配合,因为线程池的核心思想就是生产者和消费者模型,线程和任务解耦
3、通过Callable+FutureTask+Runnable创建线程
// 使用FutureTask配合Callable、Thread
FutureTask<Integer> task = new FutureTask<>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
log.debug("ts running");
Thread.sleep(3000);
return 100;
}
});
Thread t3 = new Thread(task,"t3");
t3.start();
log.debug("{}",task.get());
这种方式更前两种的最大不同就是,通过Callable创建线程可以获得一个返回结果,而FutureTask包装了这个返回结果,可以通过get()方法得到线程的执行情况。
- FutureTask实现了Runnable接口
public class FutureTask<V> implements RunnableFuture<V>
- Callable接口的call()方法具有返回值
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
- 通过向FutureTask的构造方法传入Callable对象创建对象
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
- FutureTask对象中的run()方法会调用Callable的call()方法执行任务
- FutureTask的get()方法会阻塞等待线程执行完成
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}