创建线程的8种方法,90%的人不知道

在Java开发中,线程是并发编程中的核心工具。\n\n无论是为了提高程序运行效率,还是为了处理复杂的并发任务,我们都需要在代码中使用线程。\n\n但如果你只知道 Thread 和 Runnable 两种方式,那可就有点落后了。\n\n其实,Java 提供了多种方式来创建线程,每一种都有其独特的优势和适用场景。\n\n这篇文章将从浅入深,详细剖析 Java 创建线程的8种方法,希望对你会有所帮助。\n\n1. 继承 Thread 类\n直接继承 Thread 类,重写 run() 方法,将任务逻辑写在 run() 中。\n\n通过调用 start() 方法启动线程。\n\n示例代码\nclass MyThread extends Thread {\n    @Override\n    public void run() {\n        System.out.println(\"线程名称:\" + Thread.currentThread().getName() + \" 正在执行任务\");\n    }\n}\n \npublic class ThreadExample {\n    public static void main(String[] args) {\n        MyThread thread1 = new MyThread();\n        MyThread thread2 = new MyThread();\n        thread1.start(); // 启动线程\n        thread2.start();\n    }\n}\n场景解析\n继承 Thread 是最简单的方式,非常适合初学者学习线程的基本原理。\n\n但这种方式扩展性差,因为 Java 是单继承语言,继承了 Thread 后就不能再继承其他类。\n\n优缺点\n优点: 简单直观,适合小型任务。\n\n缺点: 限制了类的继承,无法复用已有的逻辑。\n\n2. 实现 Runnable 接口\n实现 Runnable 接口,将任务逻辑写在 run() 方法中。\n\n通过 Thread 构造方法将 Runnable 对象传入,启动线程。\n\n示例代码\nclass MyRunnable implements Runnable {\n    @Override\n    public void run() {\n        System.out.println(\"线程名称:\" + Thread.currentThread().getName() + \" 正在执行任务\");\n    }\n}\n \npublic class RunnableExample {\n    public static void main(String[] args) {\n        Thread thread1 = new Thread(new MyRunnable());\n        Thread thread2 = new Thread(new MyRunnable());\n        thread1.start();\n        thread2.start();\n    }\n}\n场景解析\n相比继承 Thread,实现 Runnable 接口更灵活,避免了单继承的限制。大多数开发场景中,更推荐使用这种方式。\n\n优缺点\n优点: 解耦任务逻辑和线程对象,灵活性更高。\n\n缺点: 需要额外创建 Thread 对象。\n\n3. 实现 Callable 接口\nCallable 接口是 Java 5 引入的,类似于 Runnable,但它支持返回值,并可以抛出异常。\n\n示例代码\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.FutureTask;\n \nclass MyCallable implements Callable\u003CString> {\n    @Override\n    public String call() throws Exception {\n        return \"线程名称:\" + Thread.currentThread().getName() + \",任务执行完成\";\n    }\n}\n \npublic class CallableExample {\n    public static void main(String[] args) throws ExecutionException, InterruptedException {\n        FutureTask\u003CString> futureTask = new FutureTask\u003C>(new MyCallable());\n        Thread thread = new Thread(futureTask);\n        thread.start();\n \n        // 获取线程返回结果\n        System.out.println(\"线程返回结果:\" + futureTask.get());\n    }\n}\n场景解析\n如果你的线程需要返回结果,Callable 是更好的选择,比如数据查询、复杂计算等场景。\n\n优缺点\n优点: 支持返回值和异常处理,功能更强大。\n\n缺点: 代码复杂度比 Runnable 略高。\n\n我最近开源了一个基于 SpringBoot+Vue+uniapp 的商城项目,欢迎访问和star。[https://gitee.com/dvsusan/susan_mall]\n\n4. 使用线程池\n线程池是一种高效的线程管理机制,可以复用线程,减少创建和销毁线程的开销。\n\n示例代码\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n \npublic class ThreadPoolExample {\n    public static void main(String[] args) {\n        ExecutorService executorService = Executors.newFixedThreadPool(3);\n \n        Runnable task = () -> System.out.println(\"线程名称:\" + Thread.currentThread().getName() + \" 正在执行任务\");\n \n        for (int i = 0; i \u003C 5; i++) {\n            executorService.execute(task);\n        }\n \n        executorService.shutdown();\n    }\n}\n场景解析\n适用于需要高并发处理任务的场景,比如 Web 服务的请求处理。\n\n优缺点\n优点: 高效管理线程生命周期,避免频繁创建和销毁线程。\n\n缺点: 需要合理配置线程池参数,否则可能导致资源浪费。\n\n5. 使用 ScheduledExecutorService\nScheduledExecutorService 是 Java 提供的一种定时任务调度机制,可以在指定时间点或周期性地执行任务。\n\n示例代码\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n \npublic class ScheduledExample {\n    public static void main(String[] args) {\n        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);\n \n        Runnable task = () -> System.out.println(\"当前时间:\" + System.currentTimeMillis());\n \n        // 延迟1秒后,每2秒执行一次\n        scheduler.scheduleAtFixedRate(task, 1, 2, TimeUnit.SECONDS);\n \n        // 程序运行一段时间后需要手动关闭线程池\n        // scheduler.shutdown();\n    }\n}\n场景解析\n适用于周期性任务,比如定时备份、定时清理缓存等。\n\n优缺点\n优点: 易于实现定时和周期性任务。\n\n缺点: 不适合复杂调度场景。\n\n6. 使用 Fork/Join 框架\nFork/Join 是 Java 7 引入的一种并行计算框架,适合将大任务分解成多个子任务并行处理。\n\n示例代码\nimport java.util.concurrent.RecursiveTask;\nimport java.util.concurrent.ForkJoinPool;\n \nclass SumTask extends RecursiveTask\u003CInteger> {\n    private final int start, end;\n \n    public SumTask(int start, int end) {\n        this.start = start;\n        this.end = end;\n    }\n \n    @Override\n    protected Integer compute() {\n        if (end - start \u003C= 10) {\n            int sum = 0;\n            for (int i = start; i \u003C= end; i++) {\n                sum += i;\n            }\n            return sum;\n        } else {\n            int mid = (start + end) / 2;\n            SumTask leftTask = new SumTask(start, mid);\n            SumTask rightTask = new SumTask(mid + 1, end);\n            invokeAll(leftTask, rightTask);\n            return leftTask.join() + rightTask.join();\n        }\n    }\n}\n \npublic class ForkJoinExample {\n    public static void main(String[] args) {\n        ForkJoinPool pool = new ForkJoinPool();\n        SumTask task = new SumTask(1, 100);\n        System.out.println(\"总和:\" + pool.invoke(task));\n    }\n}\n场景解析\n适合大量数据的并行处理,比如递归计算。\n\n优缺点\n优点: 提高多核 CPU 的利用率。\n\n缺点: 不适合 I/O 密集型任务。\n\n7. 使用 CompletableFuture\nCompletableFuture 是 Java 8 提供的一种异步编程工具,支持链式调用,非常适合复杂任务的分解与组合。\n\n示例代码\nimport java.util.concurrent.CompletableFuture;\n \npublic class CompletableFutureExample {\n    public static void main(String[] args) {\n        CompletableFuture.supplyAsync(() -> {\n            System.out.println(\"任务执行:\" + Thread.currentThread().getName());\n            return \"任务结果\";\n        }).thenApply(result -> {\n            System.out.println(\"处理结果:\" + result);\n            return \"最终结果\";\n        }).thenAccept(System.out::println);\n    }\n}\n场景解析\n适用于异步任务链式调用,比如远程服务调用。\n\n优缺点\n优点: 功能强大,代码简洁。\n\n缺点: 学习成本较高。\n\n8. 使用 Guava 的 ListenableFuture\nGuava 提供了 ListenableFuture,对 Future 进行了增强,支持任务完成后的回调处理。\n\nimport com.google.common.util.concurrent.*;\n \nimport java.util.concurrent.Executors;\n \npublic class ListenableFutureExample {\n    public static void main(String[] args) {\n        ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(2));\n \n        ListenableFuture\u003CString> future = service.submit(() -> {\n            Thread.sleep(1000);\n            return \"任务完成\";\n        });\n \n        Futures.addCallback(future, new FutureCallback\u003CString>() {\n            @Override\n            public void onSuccess(String result) {\n                System.out.println(\"任务成功,结果:\" + result);\n            }\n \n            @Override\n            public void onFailure(Throwable t) {\n                System.out.println(\"任务失败:\" + t.getMessage());\n            }\n        }, service);\n \n        service.shutdown();\n    }\n}\n \n总结\n以上就是 Java 中创建线程的 8 种方法,每一种方法都有其适用场景和优缺点。\n\n下面给大家总结一下各自的优缺点:\n\n方法\t适用场景\t优点\t缺点\n继承Thread类\t简单任务\t直观易懂\t限制了类的继承\n实现Runnable接口\t大多数场景\t灵活,不影响继承关系\t无返回值\n实现Callable接口\t返回结果或抛异常的任务\t支持返回值\t需要配合 FutureTask 使用\n线程池(ExecutorService)\t高并发任务\t高效管理线程\t配置复杂\nScheduledExecutorService\t周期性任务\t易于实现定时调度\t不适合复杂调度\nFork/Join框架\t数据并行计算\t提高多核利用率\t不适合 I/O 密集型任务\nCompletableFuture\t异步任务链式调用\t功能强大\t学习曲线高\nGuava的ListenableFuture\t异步任务并带回调\t回调机制强大,扩展性好\t引入了第三方依赖\n希望大家在实际开发中,能根据场景选择合适的方式。\n\n比如:小任务用 Runnable,复杂计算用 Callable,高并发场景用线程池,而异步任务可以用 CompletableFuture 或 ListenableFuture等等。\n\n通过这些方法的组合,可以让你的代码更加高效、优雅!21a4207670bb4abd94b331ceebb0acd9.png

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值