三种创建线程的方式:

  1. 继承 Thread 类
  2. 实现 Runnable 接口
  3. 实现 Callable 接口

1 继承 Thread 类

创建步骤

  1. 自定义线程类
  2. 重写run()方法
  3. 调用start()方法执行线程 ```java public class MyThread extends Thread { @Override public void run() {

    1. for (int i = 0; i < 100; i++) {
    2. System.out.println("Child thread...");
    3. try {
    4. sleep(1000);
    5. } catch (InterruptedException e) {
    6. throw new RuntimeException(e);
    7. }
    8. }

    }

    public static void main(String[] args) {

    1. MyThread thread = new MyThread();
    2. thread.start();
    3. for (int i = 0; i < 100; i++) {
    4. System.out.println("Main thread...");
    5. try {
    6. sleep(1000);
    7. } catch (InterruptedException e) {
    8. throw new RuntimeException(e);
    9. }
    10. }

    } }

  1. > 注意:
  2. > - 调用`start()`方法后,子线程不一定立刻执行,要通过 CPU 调度
  3. > - `sleep()`方法需要使用`try-catch`语句
  4. 示例
  5. ```java
  6. import org.apache.commons.io.FileUtils;
  7. import java.io.File;
  8. import java.io.IOException;
  9. import java.net.URL;
  10. public class WebDownloader extends Thread {
  11. private String url;
  12. private String fileName;
  13. public WebDownloader(String url, String fileName) {
  14. this.url = url;
  15. this.fileName = fileName;
  16. }
  17. @Override
  18. public void run() {
  19. download(this.url, this.fileName);
  20. System.out.println("File downloaded: " + this.fileName + " from " + this.url);
  21. }
  22. public static void download(String url, String fileName) {
  23. try {
  24. FileUtils.copyURLToFile(new URL(url), new File(fileName));
  25. } catch (IOException e) {
  26. e.printStackTrace();
  27. throw new RuntimeException(e);
  28. }
  29. }
  30. public static void main(String[] args) {
  31. WebDownloader w1 = new WebDownloader("https://www.baidu.com/", "baidu1.html");
  32. WebDownloader w2 = new WebDownloader("https://www.baidu.com/", "baidu2.html");
  33. WebDownloader w3 = new WebDownloader("https://www.baidu.com/", "baidu3.html");
  34. w1.start();
  35. w2.start();
  36. w3.start();
  37. }
  38. }

需要导入 commons-io 包,可以使用 maven 导入:

  1. <dependency>
  2. <groupId>commons-io</groupId>
  3. <artifactId>commons-io</artifactId>
  4. <version>2.11.0</version>
  5. </dependency>

2 实现 Runnable 接口

创建步骤

  • 定义类并实现 Runnable 接口
  • 实现run()方法
  • 创建线程对象,调用start()方法

    1. public class MyThread implements Runnable {
    2. @Override
    3. public void run() {
    4. for (int i = 0; i < 100; i++) {
    5. System.out.println("Child thread...");
    6. try {
    7. Thread.sleep(1000);
    8. } catch (InterruptedException e) {
    9. throw new RuntimeException(e);
    10. }
    11. }
    12. }
    13. public static void main(String[] args) {
    14. // 创建实现了 Runnable 接口的类
    15. MyThread myThread = new MyThread();
    16. // 使用 Runnable 对象构造 Thread 类
    17. Thread thread = new Thread(myThread);
    18. thread.start();
    19. for (int i = 0; i < 100; i++) {
    20. System.out.println("Main thread...");
    21. try {
    22. Thread.sleep(1000);
    23. } catch (InterruptedException e) {
    24. throw new RuntimeException(e);
    25. }
    26. }
    27. }
    28. }

    官方的 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 { private String name;

  1. public MyCallable(String name) {
  2. this.name = name;
  3. }
  4. @Override
  5. public Boolean call() throws Exception {
  6. for (int i = 0; i < 10; i++) {
  7. System.out.println("Thread " + this.name + " running...");
  8. Thread.sleep(1000);
  9. }
  10. return false;
  11. }
  12. public static void main(String[] args) throws ExecutionException, InterruptedException {
  13. Callable<Boolean> c1 = new MyCallable("t1");
  14. Callable<Boolean> c2 = new MyCallable("t2");
  15. Callable<Boolean> c3 = new MyCallable("t3");
  16. // 创建执行服务
  17. ExecutorService ser = Executors.newFixedThreadPool(3);
  18. // 提交执行
  19. Future<Boolean> result1 = ser.submit(c1);
  20. Future<Boolean> result2 = ser.submit(c2);
  21. Future<Boolean> result3 = ser.submit(c3);
  22. boolean res1 = result1.get();
  23. boolean res2 = result2.get();
  24. boolean res3 = result3.get();
  25. ser.shutdownNow();
  26. }

}

  1. > 通过 Callable 创建线程的**好处**:
  2. > - 可以拿到线程执行的返回值
  3. > - 可以抛出异常
  4. <a name="eACvi"></a>
  5. ## %% 创建方式的比较
  6. **实践中一般通过实现 Runnable 接口来创建线程,而不使用继承 Thread 类的方式。**<br />原因如下:
  7. 1. 由于 Java 中只能单继承的局限性,一个类如果继承了 Thread 类,就不能在继承其他类
  8. 1. 使用 Runnable,可以让多个线程执行同一个 Runnable 对象的`run()`方法,可以共享同一类的变量,代码如下:
  9. ```java
  10. Callable myThread = new MyThread();
  11. // 使用同一个 Runnable 对象执行不同的线程
  12. Thread t1 = new Thread(myThread);
  13. Thread t2 = new Thread(myThread);
  14. Thread t3 = new Thread(myThread);
  15. t1.start();
  16. t2.start();
  17. t3.start();

如果需要返回值,或者线程抛出异常的情况,则应该使用 Callable 创建线程。