Java多线程 - 黑马教程

news2024/11/15 11:16:37

文章目录

  • Java 多线程
    • 一、多线程概述
    • 二、 多线程创建方式
      • 1、继承 Thread 类创建线程
      • 2、实现 Runnable 接口
      • 3、实现 Callable 接口
    • 三、Thread 常用的方法
    • 四、线程安全
      • 什么是线程安全问题?
      • 线程安全问题出现的原因
      • 程序模拟线程安全
    • 五、线程同步
      • 线程同步方式1:同步代码块
      • 线程同步方式2:同步方法
      • 线程同步方式3:Lock 锁
    • 六、线程池
      • 什么是线程池?
      • 创建线程池
        • ThreadPoolExecutor 构造器
      • 线程池创建的注意事项(面试常问)
      • 线程池处理 Runnable 任务
      • 线程池处理 Callable 接口
    • 七、使用 Executors 工具类得到线程池
    • 八、并发和并行
      • 进程
      • 并发的含义
      • 并行的含义
    • 九、线程的生命周期
      • 什么是线程生命周期?
      • Java 线程状态
      • 线程的6种状态及互相转换
      • 线程的6种状态总结

Java 多线程

一、多线程概述

  • 线程(Thread)是一个程序内部的一条执行流程
  • 程序如果有一条执行流程,就是单线程程序
  • 多线程是指从软硬件上实现的多条执行流程的技术(多条线程由 CPU 负责调度执行)。

二、 多线程创建方式

Java 是通过 java.lang.Thread 类的对象代表多线程。主要方式有三种 :

  1. 继承 Thread 类,重写 run 方法

  2. 实现 Runnable 接口

  3. 实现 Callable 接口

1、继承 Thread 类创建线程

  1. 创建子类 MyThread 继承 Thread 线程类
  2. 重写 Thread 类的 run 方法
  3. 创建的 MyThread 线程类的对象代表一个线程
  4. 调用 start() 方法启动线程(自动执行 run 方法)

示例代码:

/**
 * 1、创建子类 MyThread 继承 Thread 线程类
 */
public class MyThread extends Thread{
   

//    2、重写 Thread 类的 run 方法
    @Override
    public void run() {
   
        super.run();

//        描述线程的执行任务
        for (int i = 1; i < 9; i++) {
   
            System.out.println("子线程 MyThread 输出:" + i);
        }
    }
}


public class ThreadTest1 {
   

    //    main 方法是由一条默认的主线程负责执行
    public static void main(String[] args) {
   
//        3、创建的 MyThread 线程类的对象代表一个线程
        Thread t = new MyThread();

//        4、启动线程(自动执行 run 方法)
        t.start(); // main线程 t线程

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

测试结果:
在这里插入图片描述

继承 Thread 类创建线程 优缺点:

  • 优点:编码简单
  • 缺点:继承了 Thread 类无法继承其他类,不利于功能扩展

多线程注意事项:

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

如果调用 run 方法,那么 Thread t = new MyThread() 就会把 t 仅仅当做一个 Java 对象而不是一个线程,此时就只有一个 main 线程,程序会先执行 run 方法然后执行下面的代码;

start 方法是向 CPU 注册,告诉 CPU Thread t = new MyThread() 是一个单独的执行流程。

  1. 不要把主线程任务放在启动子线程之前,否则永远先执行主线程再执行子线程

2、实现 Runnable 接口

  1. 定义任务类,实现 Runnable 接口
  2. 重写 run 方法
  3. 创建任务对象
  4. 把任务对象交给线程对象处理

代码示例:

/**
 * 1、定义任务类,实现 Runnable 接口
 */
public class MyRunnable implements Runnable {
   

    //    2、重写 run 方法
    @Override
    public void run() {
   

        for (int i = 1; i < 9; i++) {
   
            System.out.println("子线程输出=== " + i);
        }

    }
}


public static void main(String[] args) {
   


//        3、创建任务对象
        Runnable target = new MyRunnable();

//         4、把任务对象交给线程对象处理
//        public Thread(Runnable target)
        new Thread(target).start();

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

测试结果:

在这里插入图片描述

实现 Runnable 接口的匿名内部类写法

public class ThreadTest2_2 {
   
    public static void main(String[] args) {
   

//        直接创建 Runnable 接口的匿名内部类(任务对象)
        Runnable target = new Runnable() {
   
            @Override
            public void run() {
   

                for (int i = 1; i < 9; i++) {
   
                    System.out.println("子线程输出=== " + i);
                }

            }
        };

        new Thread(target).start();

//        简化形式1
        new Thread(new Runnable() {
   
            @Override
            public void run() {
   
                for (int i = 1; i < 9; i++) {
   
                    System.out.println("子线程2输出=== " + i);
                }
            }
        }).start();

        //        简化形式2
        new Thread(() -> {
   

            for (int i = 1; i < 9; i++) {
   
                System.out.println("子线程3输出=== " + i);
            }

        }).start();


        for (int i = 1; i < 9; i++) {
   
            System.out.println("主线程输出:" + i);
        }

    }
}

3、实现 Callable 接口

假如线程执行完毕后需要一些数据的返回,前面两种方式重写的 run 方法均不能返回结果。

此时可以通过 Callable 接口和 FutureTask 类来实现。

通过源码可以看出来,@FunctionalInterface 表示他是一个函数式接口,同时定义了泛型与 call 方法泛型一致。如果在实现 Callable 的时候定义了泛型则重写 call 方法的返回类型返回类型固定,否则返回 Object
在这里插入图片描述
代码示例:

import java.util.concurrent.Callable;

/**
 * 1、定义任务类,实现 Callable 接口
 */
public class MyCallable implements Callable<String> {
   

    private int n;

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GPIO的使用--时钟使能含义--代码封装

目录 一、时钟使能的含义 1.为什么要时钟使能&#xff1f; 2.什么是时钟使能&#xff1f; 3.GPIO的使能信号&#xff1f; 二、代码封装 1.封装前完整代码 2.封装结构 封装后代码 led.c led.h key.c key.h main.c 一、时钟使能的含义 1.为什么要时钟使能&#xff1f…

关于如何解决问题?代码习惯。

警钟长鸣 从师哥身上学到的东西&#xff1a; 关于如何解决问题&#xff1f; 1、沟通&#xff1a;有效的沟通&#xff0c;将问题描述清楚&#xff0c;让老师和师哥明白你出了什么问题&#xff0c;给出建议&#xff0c;很多时候一句良言胜过自己摸索很久 2、出现问题由浅入深地…

国标GB28181安防监控平台EasyCVR录像时间轴优化步骤

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体可实现视频监控直播、视频轮播、视频录像、…

Linux系统上RabbitMQ安装教程

一、安装前环境准备 Linux&#xff1a;CentOS 7.9 RabbitMQ Erlang 1、系统内须有C等基本工具 yum install build-essential openssl openssl-devel unixODBC unixODBC-devel make gcc gcc-c kernel-devel m4 ncurses-devel tk tc xz socat2、下载安装包 1&#xff09;首先&a…

Harmony Ble蓝牙App(三)特性和属性

Ble蓝牙App&#xff08;三&#xff09;特性使用 前言正文一、获取属性列表二、属性提供者三、获取特性名称四、特性提供者五、加载特性六、源码 前言 在上一篇中我们完成了连接和发现服务两个动作&#xff0c;那么再发现服务之后要做什么呢&#xff1f;发现服务只是让你知道设备…

<Linux>(极简关键、省时省力)《Linux操作系统原理分析之linux存储管理(5)》(21)

《Linux操作系统原理分析之linux存储管理&#xff08;5&#xff09;》&#xff08;21&#xff09; 6 Linux存储管理6.6 Linux 物理空间管理6.6.1 Linux 物理内存空间6.6.2 物理页面的管理6.6.3 空闲页面管理——buddy 算法 6.7 内存的分配与释放6.7.1 物理内存分配的数据结构 6…

Design patterns--代理模式

设计模式之代理模式 我们使用Qt开发大型应用程序时&#xff0c;经常遇见大型程序启动时需要加载一些配置信息、用户末次操作信息&#xff0c;以及算法模型等数据时比较费时&#xff0c;笔者在程序启动时设计欢迎页或加载页等窗体来提示用户程序正在加载某些数据&#xff0c;加载…

基于SSM框架的《超市订单管理系统》Web项目开发(第五天)供应商管理,增删改查

基于SSM框架的《超市订单管理系统》Web项目开发&#xff08;第五天&#xff09;供应商管理&#xff0c;增删改查 上一次我们实现了多表关联查询&#xff0c;还有分页显示数据的功能。还完善了用户管理这一模块。 因此今天我们需要完成的是供应商管理模块&#xff0c;这一模块…

SQL自学通之表达式条件语句与运算

目录 一、目标 二、表达式条件语句 1、表达式&#xff1a; 2、条件 2.1、WHERE 子句 三、运算 1、数值型运算: 1.1、加法() 1.2、减法 (-) 1.3、除法&#xff08;/&#xff09; 1.4、乘法 &#xff08;*&#xff09; 1.5、取模 &#xff08;%&#xff09; 优先级别…

第24章:Kubernetes Helm Introduction

目录 1. Helm简介2. Helm Charts文件&#xff08;.tgz&#xff09;组成3. Helm核心术语&#xff1a;4. Helm常用命令&#xff1a;5. DIY简单Helm Charts参考链接 1. Helm简介 Helm用于管理Kubernetes应用程序&#xff0c;Helm Charts可以用于定义、安装和升级最复杂的Kubernet…

西南科技大学模拟电子技术实验七(集成运算放大器的非线性应用)预习报告

一、计算/设计过程 说明:本实验是验证性实验,计算预测验证结果。是设计性实验一定要从系统指标计算出元件参数过程,越详细越好。用公式输入法完成相关公式内容,不得贴手写图片。(注意:从抽象公式直接得出结果,不得分,页数可根据内容调整) 预习计算内容根据运放的非线…

Android加载AnimatedImageDrawable播放gif动态图,Kotlin

Android加载AnimatedImageDrawable播放gif动态图&#xff0c;Kotlin import android.graphics.ImageDecoder import android.graphics.ImageDecoder.OnHeaderDecodedListener import android.graphics.drawable.AnimatedImageDrawable import android.os.Bundle import android…

SVG-椭圆弧-参数转换-计算公式-标准解读

文章目录 1.简介2.基本参数2.1.椭圆的表达2.2.参数变换2.3.注意事项 3.参考资料4.总结 1.简介 为了与其他路径段表示法保持一致&#xff0c; SVG 路径中的圆弧是根据曲线上的起点和终点定义的。椭圆弧的这种端点参数化。优点是它允许与其它路径一致的语法&#xff0c;其中所有…

Spring Security 6.x 系列(9)—— 基于过滤器链的源码分析(二)

一、前言 在本系列文章&#xff1a; Spring Security 6.x 系列&#xff08;4&#xff09;—— 基于过滤器链的源码分析&#xff08;一&#xff09;中着重分析了Spring Security在Spring Boot 的自动配置、 DefaultSecurityFilterChain 的构造流程、FilterChainProxy 的构造流…

深入学习锁--Synchronized各种使用方法

一、什么是synchronized 在Java当中synchronized通常是用来标记一个方法或者代码块。在Java当中被synchronized标记的代码或者方法在同一个时刻只能够有一个线程执行被synchronized修饰的方法或者代码块。因此被synchronized修饰的方法或者代码块不会出现数据竞争的情况&#x…

Spring Boot中使用Swagger

1. 启用Swagger 1.1 启用注解扫描和文档接口 直接在POM文件引入依赖 <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version> </dependency>1.2 启动swagger-u…

ARM与大模型,狭路相逢

编辑&#xff1a;阿冒 设计&#xff1a;沐由 从去年底至今&#xff0c;伴随着OpenAI旗下ChatGPT的火爆&#xff0c;一波AI大模型推动着AI应用全面进入了大模型时代。与此同时&#xff0c;随着边缘算力的提升&#xff0c;AI大模型的部署也逐渐从云端涉入到边缘。 世界对AI算力的…

黑马一站制造数仓实战1

1. 项目目标 一站制造 企业中项目开发的落地&#xff1a;代码开发 代码开发&#xff1a;SQL【DSL SQL】 SparkCore SparkSQL 数仓的一些实际应用&#xff1a;分层体系、建模实现 2. 内容目标 项目业务介绍&#xff1a;背景、需求 项目技术架构&#xff1a;选型、架构 项目环境…

Selenium 自动化高级操作与解决疑难杂症,如无法连接、使用代理等

解决 Selenium 自动化中的常见疑难杂症 这里记录一些关于 Selenium的常用操作和疑难杂症。 有一些细节的知识点就不重复介绍了&#xff0c;因为之前的文章中都有&#xff01; 如果对本文中的知识点有疑问的&#xff0c;可以先阅读我以前分享的文章&#xff01; 知识点&…

1-4、调试汇编程序

语雀原文链接 文章目录 1、执行过程第一步&#xff1a;源程序第二步&#xff1a;编译连接第三步&#xff1a;执行 2、DOSBox运行程序第1步 进入EDIT.EXE第2步 编写源程序第3步 编译第4步 连接第5步 执行完整过程 3、DEBUG跟踪执行过程加载程序到内存执行程序debug和源程序数字…