三种创建线程的方式:
- 继承 Thread 类
- 实现 Runnable 接口
- 实现 Callable 接口
1 继承 Thread 类
创建步骤
- 自定义线程类
- 重写
run()
方法 调用
start()
方法执行线程 ```java public class MyThread extends Thread { @Override public void run() {for (int i = 0; i < 100; i++) {
System.out.println("Child thread...");
try {
sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
for (int i = 0; i < 100; i++) {
System.out.println("Main thread...");
try {
sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
} }
> 注意:
> - 调用`start()`方法后,子线程不一定立刻执行,要通过 CPU 调度
> - `sleep()`方法需要使用`try-catch`语句
示例
```java
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class WebDownloader extends Thread {
private String url;
private String fileName;
public WebDownloader(String url, String fileName) {
this.url = url;
this.fileName = fileName;
}
@Override
public void run() {
download(this.url, this.fileName);
System.out.println("File downloaded: " + this.fileName + " from " + this.url);
}
public static void download(String url, String fileName) {
try {
FileUtils.copyURLToFile(new URL(url), new File(fileName));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
WebDownloader w1 = new WebDownloader("https://www.baidu.com/", "baidu1.html");
WebDownloader w2 = new WebDownloader("https://www.baidu.com/", "baidu2.html");
WebDownloader w3 = new WebDownloader("https://www.baidu.com/", "baidu3.html");
w1.start();
w2.start();
w3.start();
}
}
需要导入 commons-io 包,可以使用 maven 导入:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
2 实现 Runnable 接口
创建步骤
- 定义类并实现 Runnable 接口
- 实现
run()
方法 创建线程对象,调用
start()
方法public class MyThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("Child thread...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
// 创建实现了 Runnable 接口的类
MyThread myThread = new MyThread();
// 使用 Runnable 对象构造 Thread 类
Thread thread = new Thread(myThread);
thread.start();
for (int i = 0; i < 100; i++) {
System.out.println("Main thread...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
官方的 Thread 类也是实现了 Runnable 接口,而 Runnable 接口只规定了一个
run()
方法。
3 实现 Callable 接口
创建步骤
- 实现 Callable 接口,需要返回值类型
- 重写 call 方法,需要抛出异常
- 创建目标对象
- 创建执行服务:
ExecutorService ser = Executors.newFixedThreadPool(1);
- 提交执行:
Future<Boolean> result1 = ser.submit(t1);
- 获取执行结果:
boolean res1 = result1.get();
- 关闭服务:
ser.shutdownNow();
```java import java.util.concurrent.*;
public class MyCallable implements Callable
public MyCallable(String name) {
this.name = name;
}
@Override
public Boolean call() throws Exception {
for (int i = 0; i < 10; i++) {
System.out.println("Thread " + this.name + " running...");
Thread.sleep(1000);
}
return false;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<Boolean> c1 = new MyCallable("t1");
Callable<Boolean> c2 = new MyCallable("t2");
Callable<Boolean> c3 = new MyCallable("t3");
// 创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(3);
// 提交执行
Future<Boolean> result1 = ser.submit(c1);
Future<Boolean> result2 = ser.submit(c2);
Future<Boolean> result3 = ser.submit(c3);
boolean res1 = result1.get();
boolean res2 = result2.get();
boolean res3 = result3.get();
ser.shutdownNow();
}
}
> 通过 Callable 创建线程的**好处**:
> - 可以拿到线程执行的返回值
> - 可以抛出异常
<a name="eACvi"></a>
## %% 创建方式的比较
**实践中一般通过实现 Runnable 接口来创建线程,而不使用继承 Thread 类的方式。**<br />原因如下:
1. 由于 Java 中只能单继承的局限性,一个类如果继承了 Thread 类,就不能在继承其他类
1. 使用 Runnable,可以让多个线程执行同一个 Runnable 对象的`run()`方法,可以共享同一类的变量,代码如下:
```java
Callable myThread = new MyThread();
// 使用同一个 Runnable 对象执行不同的线程
Thread t1 = new Thread(myThread);
Thread t2 = new Thread(myThread);
Thread t3 = new Thread(myThread);
t1.start();
t2.start();
t3.start();
如果需要返回值,或者线程抛出异常的情况,则应该使用 Callable 创建线程。