• 技术面①Java多线程的四种实现方法并详细举例介绍


            本专栏主要对实习/校招遇到的技术面问题进行总结记录,下面将对某单位Java工程师(实习生)技术面的第一个问题进行详细记录与总结。

    目录

    1、问题概述

    2、Java多线程的实现方式①继承Thread类

    3、Java多线程的实现方式②实现Runnable接口

    4、Java多线程的实现方式③实现Callable接口通过FutureTask包装器来创建Thread线程

    5、Java多线程的实现方式④使用ExecutorService、Callable、Future实现有返回结果的多线程


    1、问题概述

    Q:同学你好,问你一下,Java多线程有几种实现方法?可以分别进行举例介绍吗?

    A:一共有四种

    1、继承Thread类;

    2、实现Runnable接口;

    3、实现Callable接口通过FutureTask包装器来创建Thread线程;

    4、使用ExecutorService、Callable、Future实现有返回结果的多线程。

            其中前两种方式线程执行完后都没有返回值,而后两种是带返回值的。

            在JDK5.0之前,创建线程有2种方式,一种是继承Thread类,另外一种是实现Runnable接口。这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果,也就是无返回值。如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦。自Java 1.5起,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果(有返回值)。

                            详细举例介绍(这里是便于自己理解和总结列举了四个实例)

    2、Java多线程的实现方式①继承Thread类

    实例:用继承Thread类的方法进行多线程设计。两个线程为计算和显示质数。

    1. /**
    2. * @author 蓝多多的小仓库
    3. * @title: Java多线程的实现方式①继承Thread类
    4. * @projectName ex_thread
    5. * @description: 用继承Thread类的方法进行多线程设计。两个线程为计算和显示质数。
    6. * @date 2022/7/15 19:56
    7. */
    8. class primethread extends Thread {
    9. //自定义线程类primethread继承Thread类
    10. @Override
    11. //重写run()方法,编写线程执行体
    12. public void run() {
    13. int number=3;
    14. boolean flag=true;
    15. System.out.println(2);
    16. while(true)
    17. {
    18. loop:
    19. for(int i=2;i
    20. {
    21. if((number%i)==0)
    22. {
    23. flag=false;
    24. break loop;
    25. }
    26. }
    27. if(flag)
    28. {
    29. System.out.println(number);
    30. flag=false;
    31. }
    32. number++;
    33. flag=true;
    34. try
    35. {
    36. Thread.sleep(10000);
    37. }
    38. catch(InterruptedException e)
    39. {
    40. return;
    41. }
    42. }
    43. }
    44. }
    45. public class Athread
    46. {
    47. public static void main(String args[])
    48. {
    49. //新建一个线程
    50. primethread t_Thread = new primethread();
    51. //开启线程
    52. t_Thread.start();
    53. //此为主线程,main()方法中执行的主线程
    54. while(t_Thread.isAlive())
    55. {
    56. System.out.println("Counting the prime number..");
    57. try
    58. {
    59. Thread.sleep(10000);
    60. }
    61. catch(InterruptedException e)
    62. {
    63. return;
    64. }
    65. }
    66. }
    67. }

    运行结果(这里展示两次运行的结果):

    PS:

    1>@Override的作用:

    1)可以当注释用,方便阅读;

    2)编译器可以验证@Override下面的方法名是否是父类中所有的,如果没有则报错。
    例:如果没写@Override,而下面的方法名又写错了,这时编译器是可以编译通过的,因为编译器以为这个方法是你的子类中自己增加的方法。

    2>start()方法调用后并不是立即执行多线程代码,而是使得该线程变为可运行态,什么时候运行是由操作系统决定的。从程序运行的结果可以发现,多线程程序是乱序执行。因此,只有乱序执行的代码才有必要设计为多线程。实际上所有的多线程代码执行顺序都是不确定的,每次执行的结果都是随机的。(根据两次运行结果不同可以看出)
    3>Thread.sleep()方法调用目的:不让当前线程独自霸占该进程所获取的CPU资源,以留出一定时间给其他线程执行的机会。

    3、Java多线程的实现方式②实现Runnable接口

    实例:用Runnable接口的方法进行多线程设计。线程的功能为输出正在执行的线程名。 

    1. /**
    2. * @author 蓝多多的小仓库
    3. * @title: Java多线程的实现方式②实现Runnable接口
    4. * @projectName ex_thread
    5. * @description: 用Runnable接口的方法进行多线程设计。线程的功能为输出正在执行的线程名。
    6. * @date 2022/7/15 20:16
    7. */
    8. class show_Thread implements Runnable
    9. {
    10. private String t_name;
    11. public show_Thread(String t_name)
    12. {
    13. this.t_name=t_name;
    14. }
    15. @Override
    16. //重写Run()方法
    17. public void run() {
    18. for (int i = 0; i < 20; i++) {
    19. System.out.println(t_name + "正在运行: " + i);
    20. try
    21. {
    22. Thread.sleep(1000);
    23. }
    24. catch(InterruptedException e)
    25. {
    26. return;
    27. }
    28. }
    29. }
    30. }
    31. public class Bthread {
    32. public static void main(String[] args)
    33. {
    34. new Thread(new show_Thread("T_A")).start();
    35. new Thread(new show_Thread("T_B")).start();
    36. }
    37. }

    运行结果:

    4、Java多线程的实现方式③实现Callable接口通过FutureTask包装器来创建Thread线程

    实例:遍历50以内的奇数,并对50以内奇数进行求和 

    1. import java.util.concurrent.Callable;
    2. import java.util.concurrent.ExecutionException;
    3. import java.util.concurrent.FutureTask;
    4. /**
    5. * @author 蓝多多的小仓库
    6. * @title: Java多线程的实现方式③实现Callable接口通过FutureTask包装器来创建Thread线程
    7. * @projectName ex_thread
    8. * @description: 遍历50以内的奇数,并对50以内奇数进行求和
    9. * @date 2022/7/16 20:06
    10. */
    11. class TolThread implements Callable {
    12. // 重写call()方法
    13. @Override
    14. public Integer call() throws Exception
    15. {
    16. int total = 0;
    17. for (int i=1;i<=50;i++)
    18. {
    19. if (i%2 != 0)
    20. {
    21. System.out.println(i);
    22. total += i;
    23. }
    24. }
    25. return total;
    26. }
    27. }
    28. public class Cthread {
    29. public static void main(String[] args) {
    30. //创建Callable接口实现类的对象
    31. TolThread tolThread = new TolThread();
    32. //将该Callable实现类的对象作为参数传到FutureTask构造器中,创建FutureTask的对象
    33. FutureTask futureTask = new FutureTask(tolThread);
    34. //将FutureTask的对象作为参数传到Thread类的构造器中,创建Thread对象,并调用start方法
    35. new Thread(futureTask).start();
    36. try {
    37. //get方法的返回值为FutureTask构造器参数Callable实现类重写的call方法的返回值。
    38. System.out.println("总和为:"+futureTask.get());
    39. }
    40. catch (InterruptedException e)
    41. {
    42. e.printStackTrace();
    43. }
    44. catch (ExecutionException e)
    45. {
    46. e.printStackTrace();
    47. }
    48. }
    49. }

    运行结果:

    PS:

            与使用Runnable相比, Callable功能更强大些:1>相比run()方法,可以有返回值2>方法可以抛出异常3>支持泛型的返回值4>需要借助FutureTask类,比如获取返回结果。

    5、Java多线程的实现方式④使用ExecutorService、Callable、Future实现有返回结果的多线程

    实例参考:https://blog.csdn.net/pdw2009/article/details/87939915

    1. /**
    2. * @author 蓝多多的小仓库
    3. * @title: Java多线程的实现方式④使用ExecutorService、Callable、Future实现有返回结果的多线程
    4. * @projectName ex_thread
    5. * @description: 代码来源:https://blog.csdn.net/pdw2009/article/details/87939915
    6. * @date 2022/7/16 20:50
    7. */
    8. import java.util.ArrayList;
    9. import java.util.List;
    10. import java.util.concurrent.Callable;
    11. import java.util.concurrent.ExecutionException;
    12. import java.util.concurrent.ExecutorService;
    13. import java.util.concurrent.Executors;
    14. import java.util.concurrent.Future;
    15. public class Dthread {
    16. public static void main(String[] args) {
    17. //创建一个线程池
    18. ExecutorService pools = Executors.newFixedThreadPool(5);
    19. List> list = new ArrayList>();
    20. //创建多个有返回值的任务
    21. for(int i = 0 ; i <= 10 ; i++){
    22. Future futures = pools.submit(new Task(i));
    23. list.add(futures);
    24. }
    25. for(Future f : list){
    26. try {
    27. System.out.println(f.get());
    28. } catch (InterruptedException e) {
    29. e.printStackTrace();
    30. } catch (ExecutionException e) {
    31. e.printStackTrace();
    32. }
    33. }
    34. pools.shutdown();
    35. }
    36. }
    37. class Task implements Callable
    38. {
    39. private Integer taskID;
    40. public Task(Integer taskID) {
    41. this.taskID = taskID;
    42. }
    43. public Integer call() throws Exception {
    44. if(taskID.equals(3))
    45. Thread.sleep(1000);
    46. System.out.println("任务["+taskID+"]开始执行");
    47. return taskID;
    48. }
    49. }

    运行结果:

    PS:

            可返回值的任务必须实现Callable接口。类似的,无返回值的任务必须实现Runnable接口。执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了。

  • 相关阅读:
    猿创征文|枚举类增强型for循环遍历
    c#手动签字实现
    Hive修改Parquet类型表字段几种问题处理
    184:vue+openlayers 设置时间显示白天黑夜交替图
    【算法|动态规划No.11】leetcode53. 最大子数组和
    锂电溶液提纯除钙镁用什么工艺,除钙镁树脂设备
    《中国数字经济发展指数报告(2023年)》发布
    机器视觉应用系统包括哪些硬件?
    toB应用私有化交付发展历程、技术对比和选型
    Net Core API +Vue Nginx集成发布
  • 原文地址:https://blog.csdn.net/qq_43554335/article/details/125825086