创建线程的三种方式
废话不说,直接上代码
继承Thread类
// 继承Thread
class MyThread extends Thread {
// 重写run方法执行任务
@Override
public void run() {
for (int i = 0; i < 10; i++) {
// 可以通过this拿到当前线程
System.out.println(this.getName()+"执行了"+i);
}
}
}
public class Demo_02_02_1_ThreadCreateWays {
public static void main(String[] args) {
// 先new出来,然后启动
MyThread myThread = new MyThread();
myThread.start();
for (int i = 0; i < 10; i++) {
// 通过Thread的静态方法拿到当前线程
System.out.println(Thread.currentThread().getName()+"执行了"+i);
}
}
}
实现Runnable
// 实现Runnable接口
class MyThreadByRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
// 不能用this了
System.out.println(Thread.currentThread().getName() + "执行了" + i);
}
}
}
public class Demo_02_02_1_ThreadCreateWays {
public static void main(String[] args) {
// 实现Runnable接口的方式启动线程
Thread thread = new Thread(new MyThreadByRunnable());
thread.start();
for (int i = 0; i < 10; i++) {
// 通过Thread的静态方法拿到当前线程
System.out.println(Thread.currentThread().getName() + "执行了" + i);
}
}
}
用lamba也可以
new Thread(() -> {
System.out.println("Runnable是函数式接口, java8也可以使用lamba");
}).start();
使用Callable和Future
// 使用Callable
class MyThreadByCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"执行了"+i);
sum+=i;
}
return sum;
}
}
public class Demo_02_02_1_ThreadCreateWays {
public static void main(String[] args) {
// 用FutureTask包一层
FutureTask<Integer> futureTask = new FutureTask<>(new MyThreadByCallable());
new Thread(futureTask).start();
try {
// 调用futureTask的get能拿到返回的值
System.out.println(futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
这是最复杂的一种方式,他可以有返回值,归纳一下步骤:
- 搞一个类实现
Callable
接口,重写call
方法,在call
执行任务 - 用
FutureTask
包装实现Callable
接口类的实例 - 将
FutureTask
的实例作为Thread
构造参数 - 调用
FutureTask
实例的get
拿到返回值,调这一句会阻塞父线程
Callable
也是函数式接口,所以也能用lamba
为啥Thread构造里边能方Runnable,也能放FutureTask? 其实FutureTask继承RunnableFuture,而RunnableFuture继承Runnable和Future,注意接口是可以多继承的
三种方式比较
方式 | 使用简易程度 | 是否可以共享任务代码 | 是否可以有返回值 | 是否可以声明抛出异常 | 是否可以再继承别的类 |
---|---|---|---|---|---|
继承Thread | 简单 | 不能 | 不能 | 不能 | 不能 |
Runnable | 中等 | 可以 | 不能 | 不能 | 可以 |
Callable | 复杂 | 可以 | 可以 | 可以 | 可以 |
继承Thread
是最容易的,但是也是最不灵活的
使用Callable
时最复杂的,但是也是最灵活的
这里说的共享任务代码举个例子:
还是上面那个MyThreadByRunnable
类
MyThreadByRunnable myThreadByRunnable = new MyThreadByRunnable();
Thread thread = new Thread(myThreadByRunnable);
thread.start();
// 再来一个,复用了任务代码,继承Thread就不行
Thread thread2 = new Thread(myThreadByRunnable);
thread2.start();