• 2023.10.7 Java 创建线程的七种方法


    目录

    继承 Tread 类,重写 run 方法

    实现 Runnable 接口 

    使用匿名内部类,继承 Thread 类

    使用匿名内部类,实现 Runable 接口

    使用 Lambda 表达式

    使用线程池创建线程

    实现 Callable 接口 


    继承 Tread 类,重写 run 方法

    • 自定义一个 MyThread类,用来继承 Thread 类,重写 run 方法,最后在 main 方法中new 出 MyThread 实例,并调用该实例继承自父类 Thread 类的 start 方法,从而创建一个新线程
    1. //先创建一个类 让该类继承 Thread 父类
    2. class MyThread extends Thread {
    3. // 重写 run 方法
    4. @Override
    5. public void run() {
    6. System.out.println("在 run方法中 自定义线程的工作内容");
    7. }
    8. }
    9. public class ThreadDemo1 {
    10. public static void main(String[] args) {
    11. // 创建实例t
    12. Thread t = new MyThread();
    13. // 启动并创建新线程
    14. t.start();
    15. // run 方法仅执行 run方法中的代码,并不会创建一个新线程
    16. // t.run();
    17. }
    18. }

    注意:

    • 创建实例并不会直接创建一个线程,而是调用到 start 方法才会创建一个新线程
    • 一个进程至少含有一个线程,JVM 默认创建线程为 主线程(main),主线程(main)与 MyThread 创建出来的新线程为并发执行,同时执行,各执行各的

    实现 Runnable 接口 

    • 自定义一个 MyRunnable 类,用来实现 Runnable 接口,重写 run 方法,最后在 main 方法中new 出 Thread 实例,并调用该实例的 start 方法,从而创建一个新线程
    1. class MyRunnable implements Runnable {
    2. @Override
    3. public void run() {
    4. System.out.println("在 run方法中 自定义线程的工作内容");
    5. }
    6. }
    7. public class ThreadDemo2 {
    8. public static void main(String[] args) {
    9. // 这只是描述了个任务
    10. Runnable runnable = new MyRunnable();
    11. // 把任务交给线程来执行
    12. Thread t = new Thread(runnable);
    13. t.start();
    14. }
    15. }

    注意:

    • 该方式能将 线程 和 线程要干的活 之间分离开,从而达到 解耦合 的效果
    • 如果要改动代码,不用使用多线程,转而使用多进程、线程池等,此时代码的改动较小

    使用匿名内部类,继承 Thread 类

    • 直接创建 Thread 子类,同时实例化出一个对象,重写 run 方法,并调用该实例的 start 方法,从而创建一个新线程
    1. public class ThreadDemo3 {
    2. public static void main(String[] args) {
    3. Thread t = new Thread() {
    4. @Override
    5. public void run() {
    6. System.out.println("在 run方法中 自定义线程的工作内容");
    7. }
    8. };
    9. t.start();
    10. }
    11. }

    注意:

    使用匿名内部类,实现 Runable 接口

    • 使用匿名内部类,实现 Runnable 接口作为 Thead 构造方法的参数,最后调用实例的 start 方法,从而创建一个新线程
    1. public class ThreadDemo4 {
    2. public static void main(String[] args) {
    3. Thread t = new Thread(new Runnable() {
    4. @Override
    5. public void run() {
    6. System.out.println("在 run方法中 自定义线程的工作内容");
    7. }
    8. });
    9. t.start();
    10. }
    11. }

    使用 Lambda 表达式

    • lambda 本质为以一个匿名函数,()表示函数的形参,-> 为特殊语法,{ } 表示函数体,以上构成一个 lambda 表达式
    1. public class ThreadDemo5 {
    2. public static void main(String[] args) {
    3. Thread t = new Thread(() -> {
    4. System.out.println("自定义线程的工作内容");
    5. });
    6. t.start();
    7. }
    8. }

    使用线程池创建线程

    • ThreadPoolExecutor(线程池)的构造方法写起来很麻烦,但是标准库提供了一系列工程方法来简化其使用
    • 工厂模式:将产品实例的权利移交给工厂,程序员不再通过 new 来创建所需对象,而是通过工厂获取所需产品,降低了产品使用者与使用者之间的 耦合关系
    • 使用线程池不需显示的 new,而是通过 Executors 这个静态方法 new CaChedThreadPool 来完成
    • 当然使用 submit 方法,将任务提交到线程池中,线程池中会有线程来完成这些任务
    1. package Thread;
    2. import java.util.concurrent.ExecutorService;
    3. import java.util.concurrent.Executors;
    4. public class ThreadDemo6 {
    5. public static void main(String[] args) {
    6. ExecutorService pool = Executors.newCachedThreadPool();
    7. pool.submit( new Runnable() {
    8. @Override
    9. public void run() {
    10. System.out.println("在 run方法中 自定义线程的工作内容");
    11. }
    12. });
    13. }
    14. }

     实现 Callable 接口 

    • 类似于 Runnable 一样
    • Runnable 用来描述一个任务,描述的任务是 没有返回值
    • Callable 也是用来描述一个任务,描述的任务是 有返回值
    • 如果需要使用一个线程单独的计算出某个结果来,此时使用 Callable 是比较合适的

    实例理解

    • 创建线程计算 1 + 2 + 3 + ... + 1000,并返回结果
    1. import java.util.concurrent.Callable;
    2. import java.util.concurrent.ExecutionException;
    3. import java.util.concurrent.FutureTask;
    4. public class ThreadDemo30 {
    5. public static void main(String[] args) throws ExecutionException, InterruptedException {
    6. // 使用 Callable 来计算 1 + 2 + 3 + ... + 1000
    7. Callable callable = new Callable() {
    8. @Override
    9. // 相当于 Runnable 的 run 方法,run 方法返回值是 void
    10. // 此处的 call 方法返回值是 泛型参数
    11. public Integer call() throws Exception {
    12. int sum = 0;
    13. for (int i = 0; i <= 1000; i++) {
    14. sum += i;
    15. }
    16. return sum;
    17. }
    18. };
    19. FutureTask futureTask = new FutureTask<>(callable);
    20. Thread t = new Thread(futureTask);
    21. t.start();
    22. // get 方法就是获取结果
    23. // get 会发生阻塞,直到 callable 执行完毕,get 才阻塞完成,才获取到结果
    24. Integer result = futureTask.get();
    25. System.out.println(result);
    26. }
    27. }
    • 上述代码中,callable 不能直接传入到 Thread 的构造方法里,需要套上一层其他的辅助类 FutureTask
    • Thread 类的构造方法接受的是一个实现了 Runnable 接口的对象,而不是 Callable 接口的对象
    • 为了能在 Thread 中执行 Callable 任务,需要使用一个中介类来桥接它们之间的差异,即 FutureTask 类
    • FutureTask 实现了 Runnable 接口,同时也实现了 Future 接口,因此可以将 Callable 任务封装起来,使其具备了 Runnable 的特性,可以在后台线程中执行
    • 它还提供了获取计算结果的方法,如 get 方法

    运行结果

  • 相关阅读:
    Android 13 骁龙相机点击拍照流程分析(二)——点击拍照到存入相册
    两数相加——力扣
    Selenium--多表单frame切换
    Java集合之List
    由世界第一个AI软件工程师Devin引发的热潮背后----程序员到底会不会被代替?AI发展至如今是否初衷已变?
    python中的关联关系
    第2章 内容管理模块v3.1
    【计算机网络】HTTP协议
    Selenium基础:自动化你的网页交互
    6、PostgreSQL 数据类型之一:数字类型和货币类型
  • 原文地址:https://blog.csdn.net/weixin_63888301/article/details/133636377