方法一,直接使用 Thread
//创建线程,建议创建线程的时候取一个名字
Thread t = new Thread("t1"){
@Override
public void run() {
//执行的方法
System.out.println("通过 new Thread() 方法创建线程");
}
};
//设置名称
//t.setName("t1");
//启动线程
t.start();
方法二,使用 Runnable 配合 Thread
把【线程】和【任务】(要执行的代码)分开
- Thread 代表线程
- Runnable 可运行的任务(要执行的代码)
Runnable runnable = new Runnable() {
@Override
public void run() {
//要执行的任务
System.out.println("runnable");
}
};
//创建线程对象 参数1 是任务对象,参数2 是线程名称
Thread t = new Thread(runnable, "t2");
//启动线程
t.start();
方法二用 lambda 简化
Runnable runnable = () -> {
//要执行的任务
System.out.println("runnable");
};
//创建线程对象 参数1 是任务对象,参数2 是线程名称
Thread t = new Thread(runnable, "t2");
//启动线程
t.start();
System.out.println("Hello World!");
这是因为 Runnable 方法用了 @FunctionalInterface( 函数接口 ),能够使用Lambda的依据是必须有相应的函数接口(函数接口,是指内部只有一个抽象方法的接口)。
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
Thread 与 Runnable 的原理关系
源码分析
public static void test1() {
//创建线程对象
Thread t = new Thread("t1"){
@Override
public void run() {
System.out.println("Thread");
}
};
//启动线程
t.start();
}
public static void test2() {
Runnable runnable = () -> {
//要执行的任务
System.out.println("runnable");
};
//创建线程对象 参数1 是任务对象,参数2 是线程名称
Thread t = new Thread(runnable, "t2");
//启动线程
t.start();
}
test1()
直接创建了 Thread 的子类对象,重写了Thread 中的父类 run() 方法,所以最终执行的是 Thread 中的子类方法。
test2() 调用构造方法
public Thread(String name) {
init(null, null, name, 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) {
....
//传进来的runnable 对象(target) 会赋值给 Thread 中的一个成员变量
this.target = target;
}
//而成员变量的引用处
@Override
public void run() {
if (target != null) {
target.run();
}
}
所以 Runnable 走的是 Thread 自身的 run() 方法,只不过 Thread 会检查
如果你有传进来 Runnable 对象,则优先调用 Runnable 自己的 run() 方法。
但本质上 test1 和 test2 ,将来线程运行时,都走 Thread 对象中的 run 方法
#### 结论
- test1 把线程和任务合并一起,而 test2 把线程与任务分开
- 用 Runnable 容易与线程池等高级 API 配合
- 用 Runnable 使得任务类脱离了 Thread 继承体系,更灵活,因为 Java 本身推荐组合优于继承的
方法三,使用 FutureTask 配合 Thread
FutureTask 能接收 Callable 类型的参数,用来处理有返回结果的情况
FutureTask<Integer> futureTask = new FutureTask<>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("futureTask...");
Thread.sleep(2000);
return 666;
}
});
Thread t1 = new Thread(futureTask, "task");
t1.start();
System.out.println(futureTask.get());
从源码得知 FutureTask 实现了 RunnableFuture 而 RunnableFuture
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
// Future<V> 是为返回一个结果
V get() throws InterruptedException, ExecutionException;
Callable 相比于 Runnabel 可以抛出异常
@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;
参考文献:
关于Java Lambda表达式看这一篇就够了