当前位置: 首页 > article >正文

java 并发编程 (1)java中如何实现并发编程

目录

1. 继承 Thread 类

2. 实现 Runnable 接口         

3. 使用 FutureTask

4. 使用 Executor 框架

5. 具体案例


1. 继承 Thread

概述:通过继承 Thread 类并重写其 run() 方法来创建一个新的线程。

步骤

  • 创建一个继承 Thread 类的子类。
  • 重写 run() 方法,定义线程执行的任务。
  • 调用 start() 方法来启动线程。

优缺点

  • 优点:实现简单,直接继承 Thread 类即可。
  • 缺点:由于 Java 不支持多继承,如果已经继承了其他类,则不能再继承 Thread 类。

2. 实现 Runnable 接口         

概述:通过实现 Runnable 接口并重写其 run() 方法来定义线程的任务,再通过 Thread 类来启动线程。

步骤

  • 创建一个实现 Runnable 接口的类。
  • 重写 run() 方法,定义线程执行的任务。
  • 使用 Thread 类来启动线程并传递 Runnable 对象。

优缺点

  • 优点:相比于继承 Thread,实现 Runnable 可以避免继承的限制,可以实现多线程任务的复用。
  • 缺点:需要显式地将 Runnable 对象传递给 Thread,稍微多了一些步骤。

3. 使用 FutureTask

概述FutureTask 是一个用于表示异步计算结果的类,可以结合 RunnableCallable 来创建并管理多线程任务。它实现了 Runnable 接口,因此可以用于线程的启动,并可以获取任务的执行结果。

步骤

  • 创建一个实现 Callable 接口的任务类(如果需要返回值)。
  • 使用 FutureTask 包装该任务。
  • 使用 ThreadExecutorService 来执行 FutureTask

优缺点

  • 优点:可以返回结果并处理异常,适用于需要获取计算结果的任务。
  • 缺点:相较于 Runnable,稍微复杂一些,适用于复杂任务或异步计算。

4. 使用 Executor 框架

概述Executor 框架提供了一种更高层次的线程池管理方式。它通过 ExecutorService 接口来管理线程池中的线程,实现任务的提交、调度、管理等。

步骤

  • 创建一个线程池,例如通过 Executors.newFixedThreadPool() 创建一个固定大小的线程池。
  • 提交任务到线程池,任务可以是实现了 RunnableCallable 的任务。
  • 通过 ExecutorServicesubmit()execute() 方法来提交任务。

优缺点

  • 优点:线程池管理线程,减少了创建和销毁线程的开销,能够控制最大线程数,适用于大量任务的执行。
  • 缺点:需要更多的配置和理解,适合中大型项目中的多线程任务管理。

5. 具体案例

package com.lirui.springbootmoduledemo.controller;

import java.util.concurrent.*;

public class test {

    public static void main(String[] args) throws InterruptedException {
        long startTime = System.currentTimeMillis(); // 记录开始时间

        // 创建任务 1
        Thread task1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Task 1 started.");
                try {
                    Thread.sleep(2000);  // 模拟任务执行2秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task 1 finished.");
            }
        });

        // 创建任务 2
        Thread task2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Task 2 started.");
                try {
                    Thread.sleep(1000);  // 模拟任务执行1秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task 2 finished.");
            }
        });

        // 创建任务 3
        Thread task3 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Task 3 started.");
                try {
                    Thread.sleep(1500);  // 模拟任务执行1.5秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task 3 finished.");
            }
        });

        // 启动任务
        task1.start();
        task2.start();
        task3.start();

        // 等待所有线程执行完毕
        task1.join();
        task2.join();
        task3.join();

        long endTime = System.currentTimeMillis(); // 记录结束时间
        System.out.println("All tasks finished.");
        System.out.println("Total time taken: " + (endTime - startTime) + " milliseconds");
    }


    public static void main(String[] args) throws InterruptedException {
        long startTime = System.currentTimeMillis(); // 记录开始时间

        // 执行任务 1
        System.out.println("Task 1 started.");
        Thread.sleep(2000);  // 模拟任务执行2秒
        System.out.println("Task 1 finished.");

        // 执行任务 2
        System.out.println("Task 2 started.");
        Thread.sleep(1000);  // 模拟任务执行1秒
        System.out.println("Task 2 finished.");

        // 执行任务 3
        System.out.println("Task 3 started.");
        Thread.sleep(1500);  // 模拟任务执行1.5秒
        System.out.println("Task 3 finished.");

        long endTime = System.currentTimeMillis(); // 记录结束时间
        System.out.println("All tasks finished.");
        System.out.println("Total time taken: " + (endTime - startTime) + " milliseconds");
    }
}

        从上面的案例中可以明显看出,并发执行和顺序执行在速度上的差距。具体来说,在 单线程 执行的情况下,任务是按顺序依次执行的,每个任务必须等待前一个任务完成后才能开始,因此总的执行时间是所有任务执行时间的累加。而在 多线程 执行的情况下,任务是并行执行的,多个任务可以同时进行,特别是在多核处理器上,线程可以在不同的 CPU 核心上并行运行,这大大缩短了总的执行时间。通过这种方式,任务 1、2 和 3 的执行时间是重叠的,最终的执行时间仅取决于最长的任务。因此,在并发执行的情况下,程序的总执行时间显著减少,相比顺序执行,性能提升尤为明显,尤其当任务之间的执行时间差异较大时,效果更加突出。


http://www.kler.cn/a/405564.html

相关文章:

  • MongoDB进阶篇-索引(索引概述、索引的类型、索引相关操作、索引的使用)
  • 通过vite+vue3+pinia从0到1搭建一个uniapp应用
  • 3-22 ElementPlus:表单
  • 【PCIE常见面试问题-1】
  • 音频信号采集前端电路分析
  • 【代码pycharm】动手学深度学习v2-04 数据操作 + 数据预处理
  • Java文件上传解压
  • DICOM图像知识:解析如何在DICOM图像中实现多层覆盖层的显示的方法
  • dpdk poe丢包排查
  • 悬浮框元素定位
  • 移动语义和拷贝语义有什么区别?
  • Mumu模拟器12开启ADB调试方法
  • 【Zookeeper】二、主从应用(master-worker架构)
  • 0欧姆电阻的作用
  • Elasticsearch简介与实操
  • Spring Cloud Netflix 系列:Eureka 经典实战案例和底层原理解析
  • 第 27 章 - Go语言 构建命令行应用
  • 使用Python3实现Gitee码云自动化发布
  • 基于spring boot扶贫助农系统设计与实现
  • 网络安全之内网安全
  • 学习编程,学习中间件,学习源码的思路
  • UI自动化测试中公认最佳的设计模式-POM
  • Linux麦克风录音实战
  • ##继承##
  • Flink 常用问题及常用配置(有用)
  • [ 应急响应进阶篇-1 ] Windows 创建后门并进行应急处置-6:windows轻松访问后门