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

线程概述以及Java中线程的三种创建方式(继承Thread类、实现Runnable接口、实现Callable接口)

线程概述

什么是线程

线程是一个程序内部的一条执行流程

程序如果只有一条执行流程,那么这个程序就是单线程的程序

什么是多线程

多线程是指从软硬件上实现的多条执行流程的技术(多条线程由CPU负责调度执行)

如:12306同时处理多个用户请求,百度网盘下载文件的同时上传文件;再例如:消息通信、淘宝、京东系统都离不开多线程技术

如何在程序中创建出多条线程

Java通过java.lang.Thread类的对象来代表线程

创建线程的三种方式

1.方式一:继承Thread类

步骤:

在这里插入图片描述
相关代码:

package d1_create_thread;

public class ThreadTest1 {
    //main方法是由一条默认的主线程执行的
    public static void main(String[] args) {
        //3.创建MyThread线程类的对象代表一个线程
        Thread t = new MyThread();
        //4.启动线程(自动执行run方法)
        t.start();

        for (int i = 0; i <= 5; i++) {
            System.out.println("主线程main输出"+i);
        }
    }

package d1_create_thread;

/**
 * 让子类继承Thread线程类
 */
public class MyThread extends Thread{
    //2.必须重写Thread类的run方法

    @Override
    public void run() {
        //描述线程的执行任务
        for (int i = 0; i <= 5; i++) {
            System.out.println("子线程MyThread输出"+i);
        }
    }

运行结果(每次的运行结果都可能不一样):
在这里插入图片描述

优缺点:
在这里插入图片描述

多线程注意事项:

1.启动线程必须是调用start方法,不是调用run方法

调用run()方法的话,相当于还是相当于只有一条主线程,会把我们的MyThread对象就当成普通的Java对象,这样就会先执行run方法,再执行main方法。相当于并没有执行多线程

此时的运行结果(每次的运行结果都一样):
在这里插入图片描述
为什么呢

t.start()可以向操作系统CPU注册Thread t = new MyThread();线程,作为一条单独的执行流程

2.不要把主线程任务放在启动子线程之前

这样会导致永远是主线程的任务先执行完,再执行子线程

在这里插入图片描述

2.方式二:实现Runnable接口

步骤:
在这里插入图片描述

相关代码:

/**
 * 1、定义一个任务类,实现Runnable接口
 */
public class MyRunnable implements Runnable {
    //2、重写Runnable的run方法
    @Override
    public void run() {
        //线程要执行的任务
        for (int i = 0; i <= 5; i++) {
            System.out.println("子线程MyRunnable输出"+i);
        }
    }
/**
 * 实现Runnable接口
 */
public class ThreadTest2 {
    public static void main(String[] args) {
        //3、创建任务对象
        Runnable target = new MyRunnable();
        //4、把任务对象交给一个线程对象来处理(Thread中有Runnable相关的构造方法)
        //public Thread(Runnable target)
        new Thread(target).start();

        for (int i = 0; i <= 5; i++) {
            System.out.println("主线程main输出"+i);
        }
    }

运行结果:
在这里插入图片描述
优缺点:
在这里插入图片描述
(缺点可以忽略不计)

方式二的匿名内部类写法

步骤:
在这里插入图片描述
相关代码:

package d1_create_thread;

/**
 * 匿名内部类写法
 */
public class ThreadTest2_2 {
    public static void main(String[] args) {
        //1、直接创建Runnable接口的匿名内部类形式(任务对象),Runnable属于接口,是不能直接new的
        Runnable target = new Runnable() {
            @Override
            public void run() {
                //线程要执行的任务
                for (int i = 0; i <= 5; i++) {
                    System.out.println("子线程输出"+i);
                }
            }
        };
        new Thread(target).start();

        for (int i = 0; i <= 5; i++) {
            System.out.println("主线程main输出"+i);
        }
    }
}

运行结果:
在这里插入图片描述

3.方式三:实现Callable接口

前两种线程创建方式都存在的一个问题:
假如线程执行完毕后有一些数据需要返回,他们重写的run方法均不能直接返回结果。(因为重写的是public void run()

步骤:
在这里插入图片描述
代码实现:

/**
 * 1、实现Callable接口
 */
public class MyCallable implements Callable<String> {
    private int n;

    public MyCallable(int n) {
        this.n = n;
    }

    //2、重写call方法
    @Override
    public String call() throws Exception {
        //描述线程的任务,返回线程执行返回后的结果
        //需求:求1~n的和并返回
        int sum = 0;
        for (int i = 0; i <= n; i++) {
            sum += i;
        }
        return "线程求出1~"+"n"+"的和为"+sum;
    }
}
public class ThreadTest3 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //3、创建一个Callable的对象
        Callable<String> call = new MyCallable(100);
        //4、把Callable对象封装成FutureTask对象(任务对象)
        // 未来任务对象的作用?
        // ①是一个任务对象,实现了Runnable
        // ②可以在线程执行完毕之后,用未来对象调用get方法获取线程执行完毕后的结果
        FutureTask<String> f1 = new FutureTask<String>(call);
        //5、把任务对象交给一个Thread对象
        new Thread(f1).start();
        //6、获取线程执行完毕后返回的结果
        //注意:如果执行到这儿,假如上面的线程还没有执行完毕
        //这里的代码会暂停,等待上面线程执行完毕后才会获取结果。
        String rs = f1.get(); //直接抛出异常
        System.out.println(rs);
    }
}

运行结果:
在这里插入图片描述

FutureTask的API:
在这里插入图片描述
优缺点:

优点: 线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强 ; 可以在线程执行完毕后去获取线程执行的结果

缺点:代码较复杂

参考视频:https://www.bilibili.com/video/BV1g8411o7aj

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dtcms.com/a/42870.html

相关文章:

  • 鸿蒙 ArkUI 实现 2048 小游戏
  • 网络安全 越权分为几种
  • Centos7源码编译安装Sqlite最新版本
  • 算法-二叉树篇14-从中序与后序遍历序列构造二叉树
  • 深度解析 ANSI X9.31 TR-31:金融行业密钥管理核心标准20250228
  • 如何有效判断与排查Java GC问题
  • Spring 源码硬核解析系列专题(十):Spring Data JPA 的 ORM 源码解析
  • 【Spring】AOP
  • PMP项目管理—范围管理篇—6.控制范围
  • 轻松微调大模型:利用 Colab 和 Unsloth 实现高效训练
  • 企业微信里可以使用的企业内刊制作工具,FLBOOK
  • 1.2.3 使用Spring Initializr方式构建Spring Boot项目
  • Python在实际工作中的运用-指定目录内所有Excel文件转CSV
  • Qt基于信号量QSemaphore实现的生产者消费者模型
  • 【Vue3】浅谈setup语法糖
  • 手机隐私数据彻底删除工具:回收或弃用手机前防数据恢复
  • golang安装(1.23.6)
  • 智能家居遥控革命!昂瑞微HS6621EM:用「芯」定义AIoT时代的语音交互标杆
  • 【0011】HTML其他文本格式化标签详解(em标签、strong标签、b标签、i标签、sup标签、sub标签......)
  • 【企业场景】上线的项目如何进行限流
  • 为什么打开串口会发送两次指令(加强版)
  • JeeWMS graphReportController.do SQL注入漏洞复现(CVE-2025-0392)
  • 【OpenCV C++】以时间命名存图,自动检查存储目录,若不存在自动创建, 按下空格、回车、Q、S自动存图
  • 18440二维差分
  • 【开源-鸿蒙土拨鼠大理石系统】鸿蒙 HarmonyOS Next App+微信小程序+云平台
  • 微信小程序读取写入NFC文本,以及NFC直接启动小程序指定页面
  • AIP-155 请求标识
  • 标签使用笔记
  • sqli-lab
  • 【SpringBoot】数据访问技术spring Data、 JDBC、MyBatis、JSR-303校验