JAVA多线程实现的四种方式及使用场景详解

 更新时间:2025年01月18日 14:48:24   作者:日暮温柔  
这篇文章主要介绍了JAVA多线程实现的四种方式及使用场景,并举例说明了在管理系统中多线程的应用场景,如数据导入导出、数据缓存更新、并发用户操作处理、系统监控和定时任务执行,需要的朋友可以参考下

一、继承Thread类实现多线程

  • 步骤一:定义线程类
    创建一个类继承自Thread类,并重写run方法。run方法中的代码就是线程执行的内容。
    例如:
class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("MyThread: " + i);
        }
    }
}
  • 步骤二:启动线程
    在main方法或者其他合适的地方创建线程对象,然后调用start方法来启动线程。
    例如:
public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("Main Thread: " + i);
        }
    }
}

注意,不能直接调用run方法来启动线程。如果直接调用run方法,就相当于在当前线程中执行run方法中的代码,而不是开启一个新的线程。

二、实现Runnable接口实现多线程

  • 步骤一:定义任务类
    创建一个类实现Runnable接口,实现run方法。这个run方法包含了线程要执行的任务。
    例如:
java
class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("MyRunnable: " + i);
        }
    }
}

  • 步骤二:创建线程并启动
    首先创建Runnable对象,然后将其作为参数传递给Thread对象的构造函数,最后调用Thread对象的start方法来启动线程。
    例如:
public class Main {
    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);
        thread.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("Main Thread: " + i);
        }
    }
}

实现Runnable接口的优势
这种方式更灵活,因为一个类可以实现多个接口,避免了单继承的限制。例如,如果一个类已经继承了其他类,还想实现多线程功能,就可以使用实现Runnable接口的方式。而且Runnable对象可以被多个线程共享,方便在多个线程中执行相同的任务。

三、使用Callable和Future实现多线程(带有返回值)

  • 步骤一:定义Callable任务类
    创建一个类实现Callable接口,实现call方法。call方法中包含线程要执行的任务,并且可以有返回值。
    例如:
import java.util.concurrent.Callable;
class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() {
        int sum = 0;
        for (int i = 0; i < 10; i++) {
            sum += i;
        }
        return sum;
    }
}
  • 步骤二:提交任务并获取结果
    通过ExecutorService来提交Callable任务。ExecutorService可以通过Executors工厂类来创建。
    例如:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Main {
    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        MyCallable callable = new MyCallable();
        Future<Integer> future = executorService.submit(callable);
        System.out.println("计算结果: " + future.get());
        executorService.shutdown();
    }
}

在这里,submit方法提交Callable任务并返回一个Future对象,通过Future对象的get方法可以获取Callable任务的返回值。shutdown方法用于关闭ExecutorService。

四、线程池的使用(ExecutorService)

  • 步骤一:创建线程池
    可以使用Executors工厂类创建不同类型的线程池,如newFixedThreadPool(固定大小线程池)、newCachedThreadPool(可缓存线程池)、newSingleThreadExecutor(单线程线程池)等。
    例如,创建一个固定大小为 5 的线程池:
ExecutorService executorService = Executors.newFixedThreadPool(5);
  • 步骤二:提交任务到线程池
    可以使用execute方法提交Runnable任务,或者使用submit方法提交Callable任务到线程池。
    例如,提交一个Runnable任务:
class MyRunnableInPool implements Runnable {
    @Override
    public void run() {
        System.out.println("线程池中的线程在执行任务");
    }
}
public class Main {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            executorService.execute(new MyRunnableInPool());
        }
        executorService.shutdown();
    }
}
  • 步骤三:关闭线程池
    当任务执行完毕后,需要关闭线程池。可以使用shutdown方法来正常关闭线程池,它会等待所有已提交的任务执行完毕后再关闭。如果想要立即关闭线程池,可以使用shutdownNow方法,但这种方式可能会导致正在执行的任务被中断。
    例如:
executorService.shutdown();

Q:一个管理系统的java项目,什么时候会需要用到多线程呢?

1、数据导入与导出功能

背景和需求:
在管理系统中,经常需要进行数据的导入和导出操作。例如,将大量的用户信息、订单数据等从外部文件(如 CSV、Excel 文件)导入到数据库中,或者将系统中的数据导出为报表文件。这些操作可能涉及大量的数据处理,如果在单线程中执行,会导致界面长时间无响应,用户体验差。
多线程的应用方式:
可以开启一个单独的线程来执行数据导入或导出任务。这样,在数据处理的同时,用户界面仍然可以响应用户的其他操作,如查看其他数据、进行系统设置等。例如,当用户点击 “导入数据” 按钮时,系统在后台线程中读取文件、解析数据并插入到数据库,而前台线程继续响应用户的其他交互。

2、数据缓存更新与维护

背景和需求:
为了提高系统性能,管理系统通常会使用数据缓存。缓存的数据需要定期更新,以保证数据的一致性和时效性。例如,缓存的商品库存信息、用户权限信息等需要根据数据库中的最新数据进行更新。
多线程的应用方式:
可以使用一个线程定期(如每隔一段时间)检查缓存数据是否过期,并在需要时更新缓存。这个线程可以在后台默默地运行,不影响系统的其他主要功能。同时,在数据发生变化(如用户修改了商品库存)时,也可以通过多线程机制及时更新缓存,以减少对系统其他操作的影响。

3、并发用户操作处理

背景和需求:
在多用户使用的管理系统中,会有多个用户同时进行各种操作,如查询数据、修改记录、提交表单等。如果系统是单线程的,这些操作只能依次进行,效率低下。
多线程的应用方式:
为每个用户请求分配一个独立的线程来处理。例如,在一个在线商城管理系统中,当多个管理员同时修改商品价格、处理订单时,系统可以为每个管理员的操作开启一个线程,这些线程可以并发地访问和修改数据库中的数据(当然,需要注意数据库连接池的合理使用和数据的一致性问题),从而提高系统的并发处理能力。

4、系统监控与日志记录

背景和需求:
管理系统需要对自身的运行状态进行监控,如系统资源使用情况(CPU、内存、磁盘 I/O 等)、服务的可用性等。同时,需要记录用户操作日志、系统错误日志等信息。
多线程的应用方式:
可以使用一个线程专门负责系统监控,定期收集系统状态数据并进行分析。另一个线程可以负责将日志信息写入日志文件,这样可以避免日志记录操作阻塞其他业务操作,并且在系统出现问题时能够及时记录相关信息,方便后续的故障排查。

5、定时任务执行

背景和需求:
管理系统中有很多定时任务,如每天定时生成销售报表、每月定时结算员工工资等。这些任务需要在特定的时间自动执行,并且不能影响系统的正常运行。
多线程的应用方式:
通过线程池来管理定时任务线程。例如,使用 Java 中的ScheduledExecutorService来安排定时任务。系统可以根据任务的执行时间和频率,在后台线程中自动执行这些任务,而不会干扰系统的日常操作。

Q:只要继承了runnable接口,用这个类的时候就开启多线程了吗?

继承Runnable接口只是定义了任务内容
当一个类实现了Runnable接口,它仅仅是定义了一个线程要执行的任务逻辑,这个任务逻辑包含在run方法中。

例如:

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("执行自定义任务");
    }
}

上述代码定义了一个名为MyRunnable的类,它实现了Runnable接口,run方法里是具体要执行的任务。但此时,只是定义了任务,还没有开启多线程。

需要通过Thread类来启动线程执行任务

要真正开启一个新的线程来执行这个任务,需要将Runnable对象作为参数传递给Thread类的构造函数,然后调用Thread对象的start方法。例如:

java
public class Main {
    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);
        thread.start();
    }
}

在这个例子中,首先创建了MyRunnable类的一个对象runnable,然后通过new Thread(runnable)创建了一个Thread对象,这个Thread对象将执行runnable对象中定义的任务。最后,调用thread.start()方法来启动线程。如果只是创建了

Thread对象而没有调用start方法,任务也不会在新的线程中执行,和普通方法调用没有区别。

所以,仅仅继承Runnable接口并没有开启多线程,它只是提供了一种方便的方式来定义线程要执行的任务,还需要通过Thread类来实际启动线程,让任务在新的线程环境中运行。

总结

到此这篇关于JAVA多线程实现的四种方式及使用场景的文章就介绍到这了,更多相关JAVA多线程实现方式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot引入Redis报Redis command timed out两种异常情况

    SpringBoot引入Redis报Redis command timed out两种异常情况

    这篇文章主要给大家介绍了关于SpringBoot引入Redis报Redis command timed out两种异常情况的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2023-08-08
  • Springboot集成Kafka实现producer和consumer的示例代码

    Springboot集成Kafka实现producer和consumer的示例代码

    这篇文章主要介绍了Springboot集成Kafka实现producer和consumer的示例代码,详细的介绍了什么是Kafka和安装Kafka以及在springboot项目中集成kafka收发message,感兴趣的小伙伴们可以参考一下
    2018-05-05
  • java ReentrantLock并发锁使用详解

    java ReentrantLock并发锁使用详解

    这篇文章主要为大家介绍了java ReentrantLock并发锁使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • 解决Weblogic部署war找不到spring配置文件的问题

    解决Weblogic部署war找不到spring配置文件的问题

    这篇文章主要介绍了解决Weblogic部署war找不到spring配置文件的问题,具有很好的参考价值,希望对大家有所帮助。
    2021-07-07
  • Java异常处理及自定义异常详细指南

    Java异常处理及自定义异常详细指南

    异常处理是Java编程中的一个重要部分,用于处理程序执行中出现的异常情况,此外还可以自定义异常来处理特定的错误情况,掌握这些异常处理技术对于编写健壮、可靠的Java程序至关重要,需要的朋友可以参考下
    2024-10-10
  • 通过Java修改游戏存档的实现思路

    通过Java修改游戏存档的实现思路

    这篇文章主要介绍了通过Java修改游戏存档的实现思路,实现方法也很简单,因为植物大战僵尸游戏的数据文件存储在本地的存储位置是已知的,因此我们可以将实现过程拆分为三个步骤,需要的朋友可以参考下
    2021-10-10
  • mybatis的坑-integer类型为0的数据if test失效问题

    mybatis的坑-integer类型为0的数据if test失效问题

    这篇文章主要介绍了mybatis的坑-integer类型为0的数据if test失效问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • SpringBoot整合easyExcel实现CSV格式文件的导入导出

    SpringBoot整合easyExcel实现CSV格式文件的导入导出

    这篇文章主要为大家详细介绍了SpringBoot整合easyExcel实现CSV格式文件的导入导出,文中的示例代码讲解详细,具有一定的参考价值,感兴趣的小伙伴可以参考下
    2024-02-02
  • jdk11 jdk17多版本共存切换方式

    jdk11 jdk17多版本共存切换方式

    这篇文章主要介绍了jdk11 jdk17多版本共存切换方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-02-02
  • Java扩展Nginx之共享内存

    Java扩展Nginx之共享内存

    这篇文章主要介绍了Java扩展Nginx之共享内存的相关资料,需要的朋友可以参考下
    2023-07-07

最新评论