【多线程】初识线程,基础了解

news2024/11/18 9:25:33

目录

认识线程

    概念

        什么是线程?

        为啥要有线程

        进程和线程的区别

        Java 的线程 和 操作系统线程 的关系

    创建线程

        1.继承 Thread 类

        2.实现 Runnable 接口

        3.通过匿名内部类方式创建Thread与实现Runnable

       4.Lmabda表达式

Thread 类及常见方法

    Thread 的常见构造方法

     Thread 的几个常见属性

    启动一个线程-start()

    中断一个线程

    等待一个线程-join()

     获取当前线程引用

    休眠当前线程

线程的状态

    观察线程的所有状态


认识线程

    概念

        什么是线程?

一个线程就是一个 " 执行流 ". 每个线程之间都可以按照顺讯执行自己的代码 . 多个线程之间 " 同时 " 执行着多份代码。
多进程可以处理一个很大或复杂的任务,但启动进程时申请内存,申请文件资源,进程结束时释放文件,释放内存的操作非常耗时。
为了解决资源消耗问题,提出一个轻量化进程的概念(线程),创建线程时只关注要处理的任务,使用的是进程创建时申请的所有资源(类比开工厂)。
例:进程就相当于开工厂新建一个场子,需要购买地皮、拉电拉水、修建仓库等,非常的费时间;线程就相当于在原有工厂资源的基础上重新开一条生产线,不需要前期的资源申请,节省时间,更好的利用资源。

        为啥要有线程

首先 , " 并发编程 " 成为 " 刚需 ".
  • 单核 CPU 的发展遇到了瓶颈. 要想提高算力, 就需要多核 CPU. 而并发编程能更充分利用多核 CPU资源.
  • 有些任务场景需要 "等待 IO", 为了让等待 IO 的时间能够去做一些其他的工作, 也需要用到并发编程.
其次 , 虽然多进程也能实现 并发编程 , 但是线程比进程更轻量 .
  • 创建线程比创建进程更快.
  • 销毁线程比销毁进程更快.
  • 调度线程比调度进程更快.
最后 , 线程虽然比进程轻量 , 但是人们还不满足 , 于是又有了 " 线程池 "(ThreadPool) " 协程 "
(Coroutine)

        进程和线程的区别

  • 进程是包含线程的. 每个进程至少有一个线程存在,即主线程。
  • 进程和进程之间不共享内存空间. 同一个进程的线程之间共享同一个内存空间.
  • 进程是系统分配资源的最小单位,线程是系统调度的最小单位。

        Java 的线程 和 操作系统线程 的关系

线程是操作系统中的概念 . 操作系统内核实现了线程这样的机制 , 并且对用户层提供了一些 API 供用户使用( 例如 Linux pthread ).
Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进行了进一步的抽象和封装 .

    创建线程

        1.继承 Thread

public class MThread {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
    }
}

class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("这是线程运行代码");
    }
}

        2.实现 Runnable 接口

public class MRunnable {
    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);
        thread.start();
    }
}

class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println("这是线程运行代码");
    }
}

使用Runnable定义的好处:

  • 解耦,把定义线程与定义任务分开,以便修改代码统一修改
对比上面两种方法 :
  • 继承 Thread , 直接使用 this 就表示当前线程对象的引用.
  • 实现 Runnable 接口, this 表示的是 MyRunnable 的引用. 需要使用 Thread.currentThread()

        3.通过匿名内部类方式创建Thread与实现Runnable

Thread

public class Thread_Anon {
    public static void main(String[] args) {
        Thread thread = new Thread(){
            @Override
            public void run() {
                System.out.println("这是线程运行代码");
            }
        };
        thread.start();
    }
}

Runnable

public class Runnable_Anon {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("这是线程执行代码");
            }
        });
        thread.start();
    }
}

       4.Lmabda表达式

public class lambda {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("这是线程执行代码");
        });
        thread.start();
    }
}


用Lambda表达式实现的接口必须是函数式接口(接口中只有一个没有实现的方法)
使用多线程编程主要是为了充分利用CPU资源,提升程序运行效率;
但并不是所有场景使用多线程都可以提高效率

Thread 类及常见方法

Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。
每个执行流,也需要有一个对象来描述,而 Thread 类的对象就是用来描述一个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。

    Thread 的常见构造方法

     Thread 的几个常见属性

属性
获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()
  • ID 是线程的唯一标识,不同线程不会重复
  • 名称是各种调试工具用到
  • 状态表示线程当前所处的一个情况
  • 优先级高的线程理论上来说更容易被调度到
  • 关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。
  • 是否存活,即简单的理解,为 run 方法是否运行结束了
  • 线程的中断问题

    启动一个线程-start()

之前我们已经看到了如何通过覆写 run 方法创建一个线程对象,但线程对象被创建出来并不意味着线程就开始运行了。
  覆写 run 方法是提供给线程要做的事情的指令清单
  线程对象可以认为是把 李四、王五叫过来了
  而调用 start() 方法,就是喊一声: 行动起来! ,线程才真正独立去执行了。
调用 start 方法 , 才真的在操作系统的底层创建出一个线程 .

    中断一个线程

李四一旦进到工作状态,他就会按照行动指南上的步骤去进行工作,不完成是不会结束的。但有时我们需要增加一些机制,例如老板突然来电话了,说转账的对方是个骗子,需要赶紧停止转账,那张三该如何通知李四停止呢?这就涉及到我们的停止线程的方式了。
目前常见的有以下两种方式:
  1. 通过共享的标记来进行沟通
  2. 调用 interrupt() 方法来通知
public class ThreadDemo {
    private static class MyRunnable implements Runnable {
        @Override
        public void run() {
            // 两种方法均可以
            while (!Thread.interrupted()) {
                //while (!Thread.currentThread().isInterrupted()) {
                System.out.println(Thread.currentThread().getName()
                        + ": 别管我,我忙着转账呢!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println(Thread.currentThread().getName()
                            + ": 有内鬼,终止交易!");
                    // 注意此处的 break
                    break;
                }
            }
            System.out.println(Thread.currentThread().getName()
                    + ": 啊!险些误了大事");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyRunnable target = new MyRunnable();
        Thread thread = new Thread(target, "李四");
        System.out.println(Thread.currentThread().getName()
                + ": 让李四开始转账。");
        thread.start();
        Thread.sleep(10 * 1000);
        System.out.println(Thread.currentThread().getName()
                + ": 老板来电话了,得赶紧通知李四对方是个骗子!");
        thread.interrupt();
    }
}

 thread 收到通知的方式有两种:

1. 如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通
知, 清除中断标志
  • 当出现 InterruptedException 的时候 , 要不要结束线程取决于 catch 中代码的写法 . 可以选择
    忽略这个异常 , 也可以跳出循环结束线程 .
2. 否则,只是内部的一个中断标志被设置, thread 可以通过
  • Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志
  • Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志

    等待一个线程-join()

有时,我们需要等待一个线程完成它的工作后,才能进行自己的下一步工作。例如,张三只有等李四转账成功,才决定是否存钱,这时我们需要一个方法明确等待线程的结束。

     获取当前线程引用

方法
说明
public static Thread currentThread();
返回当前线程对象的引用

    休眠当前线程

因为线程的调度是不可控的,所以,这个方法只能保证实际休眠时间是大于等于参数设置的休眠时间的。
方法
说明
public static void sleep(long millis) throws InterruptedException
休眠当前线程 millis
毫秒
public static void sleep(long millis, int nanos) throws
InterruptedException
可以更高精度的休眠

线程的状态

    观察线程的所有状态

线程的状态是一个枚举类型 Thread.State
public class ThreadState {
    public static void main(String[] args) {
        for (Thread.State state : Thread.State.values()) {
            System.out.println(state);
        }
    }
}
  • NEW: 安排了工作, 还未开始行动
  • RUNNABLE: 可工作的. 又可以分成正在工作中和即将开始工作.
  • BLOCKED: 这几个都表示排队等着其他事情
  • WAITING: 这几个都表示排队等着其他事情
  • TIMED_WAITING: 这几个都表示排队等着其他事情
  • TERMINATED: 工作完成了.

 

这里只是线程的部分知识,剩下的知识总结我会后面继续发布,期待大家关注

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

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

相关文章

点评项目最后一篇:基于HyperLogLog实现UV统计

文章目录 1 HyperLogLog2 测试百万数据的统计 1 HyperLogLog 首先我们搞懂两个概念: UV:全称Unique Visitor,也叫独立访客量,是指通过互联网访问、浏览这个网页的自然人。1天内同一个用户多次访问该网站,只记录1次。…

无线键盘有几种连接方式?(USB接收器连接(无线2.4g)、蓝牙连接、wi-fi连接、红外线连接)

文章目录 无线键盘有哪几种连接方式?各连接方式优缺点 无线键盘有哪几种连接方式? 无线键盘有以下几种连接方式: 通过USB接收器连接(无线2.4g):无线键盘通过USB接收器与电脑连接,一般需要插入电…

3W字吃透:微服务 sentinel 限流 底层原理和实操

40岁老架构师尼恩的掏心窝: 现在拿到offer超级难,甚至连面试电话,一个都搞不到。 尼恩的技术社群中(50),很多小伙伴凭借 “左手云原生 右手大数据 SpringCloud Alibaba 微服务“三大绝活,拿…

MySQL 数据库 增删查改、克隆、外键 等操作

数据库中有数据表,数据表中有一条一条的记录。 可以用Navicat 等远程连接工具链接数据库,不过数据库需要开启授权。 SQL 字段数据类型 int:整型,默认长度是11 float:单精度浮点,4字节32位 double&#x…

Kyligence Zen产品体验-让大数据分析更轻松

很高兴有机会为大家分享我对 Kyligence Zen 产品的真实体验。在过去的几周中,我花费了大量时间使用这个企业级指标平台,并发现它在帮助企业处理和分析海量数据方面拥有强大的能力。 作为数据分析师,我们经常需要处理和分析大量的数据。这可能…

K8S管理系统项目实战[前端开发]-1

前端 Vue 入门与进阶 Vue ElementPlus 组件库 K8s管理系统项目实战[前端开发]-1 项目概述、框架搭建 Vue前端开发:整体布局 Vue前端开发:工作流 Vue前端开发:登录登出、部署、总结 一、项目慨述 本节是k8s管理系统项目实战的前端开发…

Endnote引用中文、英文参考文献方法(不用手敲中文文献信息)

目录 引用英文参考文献 插入中文参考文献格式 导入出错的解决方案 引用英文参考文献 打开知网的官网,选择想要导出成endnote格式的文献(在文献前面打√,即为选中状态),在导出与分析-导出文献-endnote,即…

配置Visual Studio Code连接远程服务器

目录 一、Windows用户需要先配置好本地的Remote SSH相关服务 二、打开VS Code,在扩展中搜索"Remote - SSH"并安装​编辑 三、详细操作 四、在出现的config配置文件中写入以下信息 五、点击VSCode界面最左侧的远程资源管理器 六、输入密码&#xff0…

记录一个特殊场景下,修改代码,idea 需要 mvn clean install的问题

修改java代码,mvn clean install 才能生效的场景,在网上看到一些方法,但是都没有生效。eg: 删除.idea, 删除后重新导入。每次修改代码测试的时候都要手动 clean install才可以,比较麻烦。 跑代码的时候,自…

HALCON多线程框架

1.整体架构 HALCON多线程处理框架基本思想是单独一个线程获取待处理图像,若干个图像处理线程并行执行 2.架构图 3.HALCON多线程并行相关算子 broadcast_condition clear_barrier clear_condition clear_event clear_message clear_message_queue clear_mutex cre…

Mac 安装 Python3.10 和 配置环境

Mac 安装 Python3.10 并且配置环境 一、Python的安装 访问官网:https://www.python.org/选择系统(Mac): [https://www.python.org/downloads/macos/] 3.选择一个版本下载。我这里选择了3.10.X 下载页面:https://www.python.or…

Qt Creator 快捷键

一、快捷键 下面是Qt常用快捷键用法,如下: 1、构建 快捷键功能ctrl/注释ctrlr运行ctrlb编译 2、查找 快捷键功能ctrlf单文件查找ctrlshiftf多文件查找ctrlshiftu查找所有使用该符号的地方(先选中某个符号,执行快捷键&#xff0…

句子扩写软件-文案扩写软件

什么是扩写软件 扩写软件是一种工具,可以帮助用户对一段文本进行扩展,增加文本的长度和信息量,同时保持原始内容的基本意思和结构不变。简单来说,扩写软件就是通过自然语言处理技术,对原始文本进行修改或补充&#xf…

搭建一个SpringSecurity项目

首先需要有一点的SpringBoot基础再来搭建会更好一点 springsecurity项目主要用于权限,验证等操作,非常方便 选择新建项目——选择spring Initializr项目 相对应的设置大家可以自行设置然后点击下一步 这里我选择两个依赖,也不用过多&#xff…

java实现mysql两个数据库对比表结构是否一致

【使用场景】 本地开发完后,增加或者删除了字段,或者修改了字段属性。 如何判定现场环境和本地环境的数据表结构一致性? 肉眼看的话,实在是一个大的工作量,所以开发了此工具。 【类存放路径】 CompareDbMain是主函数…

Spring更简单的存取Bean

在上一篇blog里边我介绍了spring项目的创建以及Bean对象的存储和读取。 存储:1.首先创建Bean对象 2.将Bean对象注册到Spring容器中【Bean标签】 读取:1.获取Spring上下文对象 2.获取指定的Bean对象 3.使用Bean对象 但是随着Bean对象的增多以及使用频率的…

【面试】Java 反射机制(常见面试题)

文章目录 前言一、反射是什么?二、为什么要有反射三、反射 API3.1 获取 Class 对象的三种方式3.2 获取成员变量3.3 获取构造方法3.4.获取非构造方法 四、实践五、常见面试题5.1. 什么是反射?5.2. 哪里用到反射机制?5.3. 什么叫对象序列化&…

IDEA沉浸式编程体验

前言 IntelliJ IDEA:前不久推出了一个新的概念Fleet编辑器。用过的人都知道,不过是模仿VScode整一套,但相比之下,fleet虽然在传统IDEA的基础上简约了不少,一旦打开智能模式,那内存占用刷一下就上去了,没个3…

Apache Atlas(1):Atlas 入门

1 Atlas 概述 Apache Atlas 为组织提供开放式元数据管理和治理功能,用以构建其数据资产目录,对这些资产进行分类和管理,形成数据字典。并为数据分析师和数据治理团队,提供围绕这些数据资产的协作功能。 注:数据字典&…

SpringBoot3 integrate SpringDoc

SpringDoc 官方文档 Springdoc3取代swagger2 pom xml加载Springdoc JarOpenAPIDefinition&#xff0c;声明一个OpenAPI对API进行分组&#xff0c;方便查询访问地址springdoc ConfigurationRequestMapping pom xml加载Springdoc Jar <dependency><groupId>org.sprin…