创建线程的三种方式
通过Thread创建线程
代码如下:
public static void main(String[] args) {
// 使用匿名子类的方法创建Thread子类对象(也可以创建一个类继承自Thread类 然后重写run方法来实现)
Thread thread1 = new Thread() {
@Override
public void run() {
log.debug("hahah");
}
};
thread1.setName("myThread 1");
thread1.start();
log.debug("heheh");
//使用内部类的方法创建Thread子类对象
//以下代码完全等价与上面
class MyThread extends Thread{
@Override
public void run() {
log.debug("hahah");
}
}
Thread thread2 = new MyThread();
thread2.setName("myThread 2");
thread2.start();
log.debug("heheh");
}
通过Ruuable接口创建线程
- Runnable接口源码
@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();
}
Runnable接口是一个函数式接口,所谓函数式接口就是只包含一个抽象方法的接口。
函数式接口可以通过lambda简化
代码如下
public class Case2 {
public static void main(String[] args) {
// 通过匿名类的方式 创建 实现Runnable接口的 对象
Runnable runnable = new Runnable() {
public void run() {
log.debug("Runnable run() haha");
}
};
// 创建线程
Thread thread1 = new Thread(runnable, "myThread 1");
// 运行
thread1.start();
// 主线程中的方法
log.debug("Case2 hehe");
// 可以使用lambda简化上述代码 (功能完全一样)
// 创建对象
// Runnable runnable2 = () -> log.debug("haha lambda");
// 创建线程
// Thread thread2 = new Thread(runnable2, "myThread 2");
// 运行
// thread2.start();
// 主线程中的方法
// log.debug("Case2 hehe");
}
}
Runnable创建线程的本质
new Thread(runnable, "myThread 1”);
构造方法源码如下
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
init源码如下
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
核心this.target = target;
@Override
public void run() {
if (target != null) {
target.run();
}
}
在这里会判断targer是否为空,若不为空则run()调用的是target的方法,也就是调用了Runnable接口实现的方法。(而使用Thread的方式则对run方法进行了重写,直接使用了重写后的run方法)故以上两种方法的本质是相同的。
两种方式的对比分析
- Thread是把线程和任务合并在了一起
- Runnable是把线程和任务分开了,用 Runnable 更容易与线程池等高级 API 配合
- 用 Runnable 让任务类脱离了 Thread 继承体系,更灵活
通过FutureTask创建线程
FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况
@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的源码
public class FutureTask<V> implements RunnableFuture<V>
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();
}
创建线程的代码如下
public class Case3 {
public static void main(String[] args) throws Exception{
FutureTask<Integer> ft = new FutureTask<Integer>(() -> {
log.debug("future call haha");
TimeUnit.SECONDS.sleep(2);
return 10086;
});
Thread ft_thread = new Thread(ft, "ft thread");
ft_thread.start();
log.debug("hehe");
// ft.get()会阻塞运行 直到得到返回结果
log.debug("{}",ft.get());
}
}