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

Java学习-----如何创建线程

        在多线程编程中,创建线程是实现并发操作的基础。不同的编程语言和开发环境提供了多种创建线程的方式,每种方式都有其独特的原理、作用、优缺点。下面将详细介绍几种常见的创建线程的方式。​

(一)继承 Thread 类​

        在 Java 中,Thread 类是线程操作的核心类,继承 Thread 类创建线程是一种基础方式。通过创建一个继承 Thread 类的子类,并重写其 run () 方法,然后实例化该子类对象,调用 start () 方法即可启动线程。​

        Thread 类实现了 Runnable 接口,其中 run () 方法是线程的执行体。当调用 start () 方法时,Java 虚拟机会为该线程分配 CPU 资源等,使其进入就绪状态,当得到 CPU 时间片后,就会执行 run () 方法中的代码。​这种方式可以方便地创建线程,通过重写 run () 方法定义线程要执行的任务,实现线程的并发执行。​

        Thread的优点主要有:​实现简单,直接继承 Thread 类,重写 run () 方法即可,无需额外实现接口。​

        而缺点则主要有:Java 是单继承机制,一个类继承了 Thread 类后,就不能再继承其他类,灵活性较差。​

        下面用一个案例简单的实现一下该继承方式:

class MyThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("线程" + Thread.currentThread().getName() + "执行:" + i);}}
}public class ThreadTest {public static void main(String[] args) {MyThread thread = new MyThread();thread.setName("线程1");thread.start();}
}

        在上述代码中,MyThread 类继承了 Thread 类,并重写了 run () 方法,在 run () 方法中定义了线程要执行的循环打印任务。在 main 方法中,创建了 MyThread 类的实例,设置线程名称后调用 start () 方法启动线程,线程启动后会执行 run () 方法中的内容。​

(二)实现 Runnable 接口​​

        实现 Runnable 接口创建线程,是让一个类实现 Runnable 接口,并重写其 run () 方法,然后将该类的实例作为参数传递给 Thread 类的构造方法,最后调用 Thread 对象的 start () 方法启动线程。​

        Runnable 接口中只包含一个 run () 方法,它定义了线程要执行的任务。当将实现了 Runnable 接口的对象传递给 Thread 类后,Thread 类的 run () 方法会调用该对象的 run () 方法,从而实现线程的执行。​这种方式可以让多个线程共享同一个实现了 Runnable 接口的对象,从而共享资源,提高资源的利用率。​

        其优缺点主要为:​

        优点:一个类可以同时实现多个接口,不影响其继承其他类,灵活性高;多个线程可以共享一个 Runnable 实例,适合多个线程处理同一份资源的场景。​

        缺点:相对于继承 Thread 类,实现过程稍显复杂,需要多一步将 Runnable 实例传递给 Thread 类的操作。​

        还是一样,用一个简单的案例来实现一下这个方法:

class MyRunnable implements Runnable {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("线程" + Thread.currentThread().getName() + "执行:" + i);}}
}public class RunnableTest {public static void main(String[] args) {MyRunnable runnable = new MyRunnable();Thread thread1 = new Thread(runnable, "线程1");Thread thread2 = new Thread(runnable, "线程2");thread1.start();thread2.start();}
}

        上述代码中,MyRunnable 类实现了 Runnable 接口,重写了 run () 方法。在 main 方法中,创建了 MyRunnable 实例,然后将其作为参数分别传递给两个 Thread 对象,设置不同的线程名称后启动线程。两个线程会共享 MyRunnable 实例,共同执行 run () 方法中的任务。​

(三)实现 Callable 接口​

        Callable 接口是 Java 5 中引入的,与 Runnable 接口类似,但它可以返回线程执行的结果,并且可以抛出异常。实现 Callable 接口创建线程时,需要与 FutureTask 类配合使用。​

        Callable 接口中的 call () 方法是线程的执行体,该方法有返回值且可以抛出异常。FutureTask 类实现了 Future 接口和 Runnable 接口,它可以接收 Callable 对象作为参数。当将 FutureTask 对象传递给 Thread 类并启动线程后,线程会执行 call () 方法,执行结果会被 FutureTask 保存,通过 FutureTask 的 get () 方法可以获取该结果。​​这种方式适合需要获取线程执行结果的场景,能够方便地处理线程执行过程中可能出现的异常。​

        Callable优缺点​主要有

        优点:可以获取线程执行结果,能抛出异常,功能更强大;同样遵循面向接口编程思想,不影响类的继承,灵活性高。​

        缺点:实现过程相对复杂,需要结合 FutureTask 类使用,获取结果的 get () 方法可能会阻塞当前线程。​

        下面是其的一个简单案例

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 1; i <= 5; i++) {sum += i;System.out.println("线程" + Thread.currentThread().getName() + "执行:" + i);}return sum;}
}public class CallableTest {public static void main(String[] args) {MyCallable callable = new MyCallable();FutureTask<Integer> futureTask = new FutureTask<>(callable);Thread thread = new Thread(futureTask, "线程1");thread.start();try {int result = futureTask.get();System.out.println("线程执行结果:" + result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}
}

        在该案例中,MyCallable 类实现了 Callable接口,重写了 call () 方法,该方法计算 1 到 5 的和并返回。创建 FutureTask 对象时将 MyCallable 实例传入,再将 FutureTask 对象作为参数创建 Thread 对象并启动线程。通过 futureTask.get () 方法可以获取 call () 方法的返回结果,该方法会阻塞当前线程直到获取到结果。​

(四)使用线程池​

        线程池是一种线程管理机制,它预先创建一定数量的线程,当有任务需要执行时,从线程池中取出一个线程来执行任务,任务执行完成后,线程不会被销毁,而是返回到线程池中等待下一个任务。使用线程池创建线程,其实是从线程池中获取线程来执行任务。​

        线程池内部维护了一个线程队列和任务队列。当提交任务时,如果线程池中有空闲线程,则立即执行任务;如果没有空闲线程,且当前线程数量未达到线程池的最大容量,则创建新线程执行任务;如果达到最大容量,则将任务放入任务队列等待,当有线程空闲时,再从任务队列中取出任务执行。​线程池可以减少线程的创建和销毁带来的开销,提高系统的性能和资源利用率,同时可以对线程进行统一管理和控制。​

        线程池的优缺点主要有:​

        优点:降低资源消耗,提高响应速度,便于线程管理(如控制最大并发数等)。​

        缺点:线程池的参数设置需要根据实际情况进行调整,设置不当可能会影响性能;对于一些简单的任务,使用线程池可能会增加一定的复杂性。​

        下面是一个简单的线程池实现:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;class MyTask implements Runnable {private int taskId;public MyTask(int taskId) {this.taskId = taskId;}@Overridepublic void run() {System.out.println("任务" + taskId + "由线程" + Thread.currentThread().getName() + "执行");}
}public class ThreadPoolTest {public static void main(String[] args) {// 创建一个固定大小为3的线程池ExecutorService executorService = Executors.newFixedThreadPool(3);for (int i = 0; i < 5; i++) {executorService.submit(new MyTask(i));}// 关闭线程池executorService.shutdown();}
}

        在上面的代码中,我们通过 Executors.newFixedThreadPool (3) 创建了一个固定大小为 3 的线程池。然后循环提交 5 个 MyTask 任务到线程池,线程池会从内部的线程中分配线程来执行这些任务。任务执行完成后,线程会返回到线程池中。最后调用 shutdown () 方法关闭线程池。​

http://www.dtcms.com/a/302298.html

相关文章:

  • 【科普】STM32CubeMX是配置工具,STM32CubeIDE是集成开发环境,二者互补但定位不同,前者负责初始化配置,后者专注代码开发调试。
  • DDD领域驱动中瘦模型与富态模型的核心区别
  • 设计模式(二十四)行为型:访问者模式详解
  • PostgreSQL日志配置全解析:从基础设置到进阶策略
  • 用 Python 获取电脑电池电量的各种案例
  • Python数据处理基础(学习笔记分享)
  • 【Spring WebFlux】 三、响应式流规范与实战
  • 科技赋能成长 脑力启迪未来
  • JVM 内存共享区域详解
  • Uniswap V2 成功上线 PolkaVM:Polkadot Hub 的里程碑时刻
  • 5190 - 提高:DFS序和欧拉序:树上操作(区域修改1)
  • 28天0基础前端工程师完成Flask接口编写
  • Ethereum:Geth运维实战,geth export与geth import命令的实用性深度评估
  • 【C++】手搓一个STL风格的vector容器
  • 【华为机试】210. 课程表 II
  • Kernel PWN 入门(二)
  • 【深度学习优化算法】10:Adam算法
  • Mybatis_4
  • 设计模式十二:门面模式 (FaçadePattern)
  • Kafka——请求是怎么被处理的?
  • 6.2 总线事务和定时 (答案见原书 P295)
  • 疏老师-python训练营-Day28类的定义和方法
  • 【LeetCode 热题 100】35. 搜索插入位置——二分查找(闭区间)
  • 区块链分叉原理与代码仿真
  • leetcode 2044. 统计按位或能得到最大值的子集数目 中等
  • 主要分布于内侧内嗅皮层的层Ⅲ的网格-速度联合细胞(Grid × Speed Conjunctive Cells)对NLP中的深层语义分析的积极影响和启示
  • 热斑漏检率↓78%!陌讯多模态算法在无人机光伏巡检的轻量化实践
  • 问题大全【1】
  • 【深度解析】R语言与作物模型(以DSSAT模型为例)融合应用
  • 散点图(散点矩阵)相关介绍