Java中实现多线程的几种方式总结

 更新时间:2025年01月08日 14:41:39   作者:夜夜流光相皎洁_小宁  
文章介绍了三种创建线程的方式:继承Thread类、实现Runnable接口和实现Callable接口,并比较了它们之间的区别和优缺点

Java实现多线程的几种方式

1)继承Thread类

实现的步骤:

  • 1)创建Thread类的子类
  • 2)重写run方法
  • 3)创建线程对象
  • 4)启动线程

代码示例:

package com.bobo.thread;

public class ThreadDemo02 {

    /**
     * 线程的第一种实现方式
     *     通过创建Thread类的子类来实现
     * @param args
     */
    public static void main(String[] args) {
        System.out.println("main方法执行了1...");
        // Java中的线程 本质上就是一个Thread对象
        Thread t1 = new ThreadTest01();
        // 启动一个新的线程
        t1.start();
        for(int i = 0 ; i< 100 ; i++){
            System.out.println("main方法的循环..."+i);
        }
        System.out.println("main方法执行结束了3...");
    }
}
/**
 * 第一个自定义的线程类
 *    继承Thread父类
 *    重写run方法
 */
class ThreadTest01 extends Thread{

    @Override
    public void run() {
        System.out.println("我们的第一个线程执行了2....");
        for(int i = 0 ; i < 10 ; i ++){
            System.out.println("子线程:"+i);
        }
    }
}

注意点:

1)启动线程是使用start方法而不是run方法

2)线程不能启动多次,如果要创建多个线程,那么就需要创建多个Thread对象

2)实现Runnable接口

在第一种实现方式中,我们是将线程的创建和线程执行的业务都封装在了Thread对象中,我们可以通过Runable接口来实现线程程序代码和数据有效的分离。

实现的步骤:

  • 1)创建Runable的实现类
  • 2)重写run方法
  • 3)创建Runable实例对象(通过实现类来实现)
  • 4)创建Thread对象,并把第三步创建的Runable实例作为Thread构造方法的参数
  • 5)启动线程

代码示例:

package com.bobo.runable;

public class RunableDemo01 {

    /**
     * 线程的第二种方式
     *     本质是创建Thread对象的时候传递了一个Runable接口实现
     * @param args
     */
    public static void main(String[] args) {
        System.out.println("main执行了...");
        // 创建一个新的线程  Thread对象
        Runnable r1 = new RunableTest();
        Thread t1 = new Thread(r1);
        // 启动线程
        t1.start();
        System.out.println("main结束了...");
    }
}

/**
 * 线程的第二种创建方式
 *   创建一个Runable接口的实现类
 */
class RunableTest implements Runnable{

    @Override
    public void run() {
        System.out.println("子线程执行了...");
    }
}

实现Runable接口的好处:

1)可以避免Java单继承带来的局限性

2)适合多个相同的程序代码处理同一个资源的情况,把线程同程序的代码和数据有效的分离,较好的体现了面向对象的设计思想

3)实现Callable接口(JDK1.5>=)

前面我们介绍的两种创建线程的方式都是重写run方法,而且run方法是没有返回结果的,也就是main方法是不知道开启的线程什么时候开始执行,什么时候结束执行,也获取不到对应的返回结果。而且run方法也不能把可能产生的异常抛出。

在JDK1.5之后推出了通过实现Callable接口的方式来创建新的线程,这种方式可以获取对应的返回结果。

代码示例:

package com.bobo.callable;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class CallableDemo01 {

    /**
     * 创建线程的第三种实现方式:
     *    Callable方式
     */
    public static void main(String[] args) throws  Exception {
        // 创建一个Callable实例
        Callable<Integer> callable = new MyCallable();
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        // 获取一个线程 肯定是要先创建一个Thread对象  futureTask本质上是Runable接口的实现
        Thread t1 = new Thread(futureTask);
        System.out.println("main方法start....");
        t1.start(); // 本质还是执行的 Runable中的run方法,只是 run方法调用了call方法罢了
        // 获取返回的结果
        System.out.println(futureTask.get()); // 获取开启的线程执行完成后返回的结果
        System.out.println("main方法end ....");

    }
}

/**
 * 创建Callable的实现类
 *    我们需要指定Callable的泛型,这个泛型是返回结果的类型
 */
class MyCallable implements Callable<Integer>{

    /**
     * 线程自动后会执行的方法
     * @return
     * @throws Exception
     */
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for(int i = 1 ; i <= 100 ; i ++){
            sum += i;
        }
        return sum;
    }
}

实现Runnable接口和实现Callable接口的区别:

  • 1)Runnable是自从java1.1就有了,而Callable是1.5之后才加上去的
  • 2)Callable规定的方法是call(),Runnable规定的方法是run()
  • 3)Callable的任务执行后可返回值,而Runnable的任务是不能返回值(是void)
  • 4)call方法可以抛出异常,run方法不可以
  • 5)运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。

4)线程池方式创建

加入线程池运行,Runnable使用ExecutorService的execute方法,Callable使用submit方法。

其实Callable接口底层的实现就是对Runable接口实现的封装,线程启动执行的也是Runable接口实现中的run方法,只是在run方法中有调用call方法罢了

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java嵌套for循环的几种常见优化方案

    Java嵌套for循环的几种常见优化方案

    这篇文章主要给大家介绍了关于Java嵌套for循环的几种常见优化,在Java中优化嵌套for循环可以通过以下几种方式来提高性能和效率,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-07-07
  • Java实现中国象棋的示例代码

    Java实现中国象棋的示例代码

    中国象棋是起源于中国的一种棋,属于二人对抗性游戏的一种,在中国有着悠久的历史。由于用具简单,趣味性强,成为流行极为广泛的棋艺活动。本文将利用Java实现这一经典游戏,需要的可以参考一下
    2022-02-02
  • Java中的Set接口实现类HashSet和LinkedHashSet详解

    Java中的Set接口实现类HashSet和LinkedHashSet详解

    这篇文章主要介绍了Java中的Set接口实现类HashSet和LinkedHashSet详解,Set接口和java.util.List接口一样,同样继承自Collection接口,它与Collection接口中的方法基本一致,并没有对Collection接口进行功能上的扩充,只是比Collection接口更加严格了,需要的朋友可以参考下
    2024-01-01
  • Java序列化机制详解

    Java序列化机制详解

    Java 序列化机制是一种将对象转换为字节流的过程,以便在网络上传输或保存到文件中,并能在需要时将字节流还原为对象,这一机制通过实现 java.io.Serializable 接口来实现,同时涉及到一些关键概念和注意事项,需要的朋友可以参考下
    2023-12-12
  • eclipse/IDEA配置javafx项目步骤(图文教程)

    eclipse/IDEA配置javafx项目步骤(图文教程)

    这篇文章主要介绍了eclipse/IDEA配置javafx项目步骤(图文教程),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • 详解Mybatis中javaType和ofType的区别

    详解Mybatis中javaType和ofType的区别

    本文主要介绍了详解Mybatis中javaType和ofType的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • Eclipse中安装反编译工具Fernflower的方法(Enhanced Class Decompiler)

    Eclipse中安装反编译工具Fernflower的方法(Enhanced Class Decompiler)

    这篇文章主要介绍了Eclipse中安装反编译工具Fernflower的方法(Enhanced Class Decompiler),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • MyBatis中RowBounds实现内存分页

    MyBatis中RowBounds实现内存分页

    RowBounds是MyBatis提供的一种内存分页方式,适用于小数据量的分页场景,本文就来详细的介绍一下,具有一定的参考价值,感兴趣的可以了解一下
    2024-12-12
  • Java 泛型总结(一):基本用法与类型擦除

    Java 泛型总结(一):基本用法与类型擦除

    本文主要介绍了Java泛型的使用以及类型擦除相关的问题。具有很好的参考价值。下面跟着小编一起来看下吧
    2017-03-03
  • Java延迟队列原理与用法实例详解

    Java延迟队列原理与用法实例详解

    这篇文章主要介绍了Java延迟队列原理与用法,结合实例形式详细分析了延迟队列的概念、原理、功能及具体使用方法,需要的朋友可以参考下
    2018-09-09

最新评论