JAVA 多线程的三种方式

JAVA 多线程的三种方式

1. 參考文章

2. 通过继承 Thread 类创建线程类

2.1. 步驟

  1. 定义一个类继承 Thread 类,并重写 Thread 类的 run()方法,run()方法的方法体就是线程要完成的任务,因此把 run()称为线程的执行体;
  2. 创建该类的实例对象,即创建了线程对象;
  3. 调用线程对象的 start()方法来启动线程;

2.2. 实现样例



// 1. 定义一个类继承Thread类,并重写Thread类的run()方法
public class DecryptThread extends Thread {

    private String batchNo;
    YmlConfig ymlConfig;
    private TaskRepository taskRepository;

    private final Logger logger = LoggerFactory.getLogger(DecryptThread.class);
// 重写的run方法中,需要什么参数,可以通过构造方法传过来;
    public DecryptThread(String batchNo, YmlConfig ymlConfig, TaskRepository taskRepository) {
        this.batchNo = batchNo;
        this.ymlConfig = ymlConfig;
        this.taskRepository = taskRepository;
    }

    public void run() {
        // 解密数据
        decrypt(batchNo, ymlConfig,taskRepository);
    }
}

public static void main(String[] args) {
    // 2. 创建该类的实例对象,即创建了线程对象;
        DecryptThread decryptThread = new DecryptThread(batchNo,ymlConfig,taskRepository);
    // 3. 调用线程对象的start()方法来启动线程;
        decryptThread.start();
}

2.3. 优点

  1. 简单直接,代码清晰。
  2. 适用于不需要共享资源的场景。每个线程的创建都要创建不同的子类对象,导致两个线程不能共享成员变量;

2.4. 缺点

  1. 由于 Java 不支持多继承,如果继承了 Thread 类,就不能继承其他类。
  2. 不适用于需要共享资源的场景,因为每个线程都是独立的 Thread 实例。

3. 实现 Runnable 接口

3.1. 步骤

  1. 创建一个类实现 java.lang.Runnable 接口。
  2. 实现 run()方法,将线程执行的任务放入 run()方法中。
  3. 创建 Runnable 实现类的实例;
  4. 创建 Thread 类的实例,并将 Runnable 实例传递给 Thread 构造函数。
  5. 调用 Thread 实例的 start()方法启动线程。
  • Runnable 实现类里包含的 run()方法仅仅作为线程执行体,而实际的线程对象依然是 Thread 实例;

3.2. 实现样例

class MyRunnable implements Runnable {
    @Override
    public void run() {
        // 线程执行的任务
        for (int i = 0; i < 5; i++) {
            System.out.println("Runnable running: " + i);
            try {
                Thread.sleep(1000); // 线程休眠1秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Main {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start(); // 启动线程
    }
}

3.3. 优点

  1. 可以实现资源共享,适用于多个线程访问同一个资源的场景。可以共同访问 run()方法中的成员变量;TODO  线程安全问题;
  2. 灵活性更高,因为可以通过实现接口来继承其他类。

3.4. 缺点

  1. 需要额外创建一个 Thread 实例,代码相对稍微复杂;

4. 使用 Callable 和 Future

4.1. 步骤

  1. 创建一个类实现 java.util.concurrent.Callable 接口。
  2. 实现 call()方法,将线程执行的任务和返回结果放入 call()方法中。
  3. 创建 Callable 实现类的实例。
  4. 创建 FutureTask 实例,并将 Callable 实例传递给 FutureTask 构造函数。
  5. 创建 Thread 类的实例,并将 FutureTask 实例传递给 Thread 构造函数。
  6. 调用 Thread 实例的 start()方法启动线程。
  7. 调用 FutureTask 实例的 get()方法获取线程执行结果。

4.2. 实现样例

  • Future 接口来代表 Callable 接口里 call()方法的返回值,并为 Future 接口提供了一个 FutureTask 实现类,该类实现了 Future 接口,并实现了 Runnable 接口,所以 FutureTask 可以作为 Thread 类的 target,同时也解决了 Callable 对象不能作为 Thread 类的 target 这一问题。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() {
        // 线程执行的任务
        int sum = 0;
        for (int i = 0; i < 5; i++) {
            sum += i;
            System.out.println("Callable running: " + i);
            try {
                Thread.sleep(1000); // 线程休眠1秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return sum; // 返回计算结果
    }
}

public class Main {
    public static void main(String[] args) {
        MyCallable myCallable = new MyCallable();
        FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
        Thread thread = new Thread(futureTask);
        thread.start(); // 启动线程

        try {
            // 获取线程执行结果
            Integer result = futureTask.get();
            System.out.println("Result: " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

4.3. 优点

  • Callable 接口,该接口是 Runnable 接口的增强版,Callable 接口提供了一个 call()方法可以作为线程执行体,
  • call()方法可以有返回值,可以声明抛出异常;
  1. 可以在线程任务完成后获取返回结果。
  2. 可以抛出异常并进行处理。

4.4. 缺点

  1. 相对来说比 Runnable 接口实现稍微复杂一些。
  2. 需要额外的 FutureTask 来包装 Callable 实例。

5. 总结

  1. 继承 Thread 类适用于简单的线程任务实现;
  2. 而实现 Runnable 接口则更灵活,适用于需要共享资源的场景。
  3. 使用 Callable 和 Future 接口不仅可以获取线程执行结果,还可以处理任务执行中的异常,更适合复杂的线程任务管理。
  • 20
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值