java基础之对线程的理解

news2025/1/21 21:50:33

目录

 

程序、进程、线程

什么是进程?

什么是线程

线程与进程的区别?

二、多线程

实现多线程方式一:继承Thread类

实现多线程方式二:实现Runnable接口

实现多线程方式三: 实现Callable接口

​ 三种实现方式的对比

设置和获取线程名称

线程休眠

线程优先级

守护线程


 

程序、进程、线程

  • 程序:程序如果不运行,就是物理磁盘上的文件,是静态的,比如我们电脑上的360.

  • 进程:是正在运行的程序,程序运行会向操作系统申请资源,进程是资源分配的基本单元。相对于程序,是动态的,比如我们电脑上的360双击运行。

  • 线程:是进程中的一条执行路径,是CPU调度执行的基本单元,一个进程下有可能包含多个线程。比如360下可以同时运行木马查杀、电脑清理等。

be65980699594cacaf1b8d64b429524b.png

什么是进程?

进程是指在计算机中运行的程序的实例。它是操作系统进行资源分配和调度的基本单位。一个进程可以包含多个线程,每个线程都共享该进程的资源,如内存、文件和打开的网络连接等。每个进程都有自己的地址空间,即独立的内存区域。

什么是线程

线程是进程内的执行单元,也是cpu的最小执行单元。一个进程可以包含多个线程,每个线程执行不同的任务。线程共享进程的资源,包括内存、文件和打开的网络连接等。线程之间通过共享内存进行通信,因此比进程间通信更高效。由于线程共享同一进程的地址空间,所以多线程之间的切换更快。

例如:我们启动JVM运行一个Java程序,其实就是启动了一个 JVM 的进程。在JVM的进程中,又包含了main :主线程、Reference Handler:清理线程、Finalizer:线程(用于调用对象 的finalize()方法)等线程。

线程与进程的区别?

根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位;

资源开销:每个进程都有独立的代码副本和数据空间,进程之间的切换,资源开销较大;线程可以看做轻量级的进程,每个线程都有自己独立的运行栈和程序计数器,线程之间切换,资源开销小;

内存分配:同一进程内的所有线程共享本进程的内存空间和资源;进程之间的内存空间和资源相互独立;

影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响;一个线程崩溃,会导致整个进程退出。所以多进程要比多线程健壮;

执行过程:每个独立的进程有程序运行的入口和程序出口。但是线程不能独立执行,必须依存在应用程序(进程)中,由应用程序提供多个线程执行控制;

包含关系:一个进程内包含有多个线程,在执行过程,线程的执行不是线性串行的,而是多条线程并行共同完成;

 

并发和并行​:

​并行:在同一时刻,有多个线程在多个CPU上同时执行。

0f1cbea1282f44eda9cdf01c9f48bc83.png

并发:在同一时刻,有多个线程在单个CPU上交替执行。

7ba5bf445a954337990c85becc9a2048.png

二、多线程

实现多线程方式一:继承Thread类

667540048b014abaab9aea220dd8e878.png

实现步骤

  • 定义一个类MyThread继承Thread类

  • 在MyThread类中重写run()方法

  • 创建MyThread类的对象

  • 启动线程

public class MyThread extends Thread {
    @Override
    public void run() {
        for(int i=0; i<100; i++) {
            System.out.println(i);
        }
    }
}
public class MyThreadDemo {
    public static void main(String[] args) {
        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();

//        my1.run();
//        my2.run();

        //void start() 导致此线程开始执行; Java虚拟机调用此线程的run方法
        my1.start();
        my2.start();
    }
}
  • 为什么要重写run()方法?

    因为run()是用来封装被线程执行的代码

  • run()方法和start()方法的区别?

    run():封装线程执行的代码,直接调用,相当于普通方法的调用

    start():启动线程;然后由JVM调用此线程的run()方法

实现多线程方式二:实现Runnable接口

d8853927c9164af1b8afd61b7a7da6b7.png

  • 实现步骤

    • 定义一个类MyRunnable实现Runnable接口

    • 在MyRunnable类中重写run()方法

    • 创建MyRunnable类的对象

    • 创建Thread类的对象,把MyRunnable对象作为构造方法的参数

    • 启动线程

  • 代码演示

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for(int i=0; i<100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}
public class MyRunnableDemo {
    public static void main(String[] args) {
        //创建MyRunnable类的对象
        MyRunnable my = new MyRunnable();

        //创建Thread类的对象,把MyRunnable对象作为构造方法的参数
        //Thread(Runnable target)
//        Thread t1 = new Thread(my);
//        Thread t2 = new Thread(my);
        //Thread(Runnable target, String name)
        Thread t1 = new Thread(my,"坦克");
        Thread t2 = new Thread(my,"飞机");

        //启动线程
        t1.start();
        t2.start();
    }
}

实现多线程方式三: 实现Callable接口

88a7be2aa8b64900b9753244efc4239a.png

public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        for (int i = 0; i < 100; i++) {
            System.out.println("跟女孩表白" + i);
        }
        //返回值就表示线程运行完毕之后的结果
        return "答应";
    }
}
public class Demo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //线程开启之后需要执行里面的call方法
        MyCallable mc = new MyCallable();

        //Thread t1 = new Thread(mc);

        //可以获取线程执行完毕之后的结果.也可以作为参数传递给Thread对象
        FutureTask<String> ft = new FutureTask<>(mc);

        //创建线程对象
        Thread t1 = new Thread(ft);

        //String s = ft.get();
        //开启线程
        t1.start();

        //获取执行之后的结果
        String s = ft.get();
        System.out.println(s);
    }
}

​ 三种实现方式的对比

  • 实现Runnable、Callable接口

    • 好处: 扩展性强,实现该接口的同时还可以继承其他的类

    • 缺点: 编程相对复杂,不能直接使用Thread类中的方法

  • 继承Thread类

    • 好处: 编程比较简单,可以直接使用Thread类中的方法

    • 缺点: 可以扩展性较差,不能再继承其他的类

设置和获取线程名称

9c8a5c2d7f424d4d9ce3f517e132bf8d.png

public class MyThread extends Thread {
    public MyThread() {}
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+":"+i);
        }
    }
}
public class MyThreadDemo {
    public static void main(String[] args) {
        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();

        //void setName(String name):将此线程的名称更改为等于参数 name
        my1.setName("高铁");
        my2.setName("飞机");

        //Thread(String name)
        MyThread my1 = new MyThread("高铁");
        MyThread my2 = new MyThread("飞机");

        my1.start();
        my2.start();

        //static Thread currentThread() 返回对当前正在执行的线程对象的引用
        System.out.println(Thread.currentThread().getName());
    }
}

线程休眠

4f0c8926705441c0b24162eb076c5d4f.png

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + "---" + i);
        }
    }
}
public class Demo {
    public static void main(String[] args) throws InterruptedException {
        /*System.out.println("睡觉前");
        Thread.sleep(3000);
        System.out.println("睡醒了");*/

        MyRunnable mr = new MyRunnable();

        Thread t1 = new Thread(mr);
        Thread t2 = new Thread(mr);

        t1.start();
        t2.start();
    }
}

线程优先级

线程调度

  • 两种调度方式

    • 分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片

    • 抢占式调度模型:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些

  • Java使用的是抢占式调度模型

  • 随机性

    假如计算机只有一个 CPU,那么 CPU 在某一个时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令。所以说多线程程序的执行是有随机性,因为谁抢到CPU的使用权是不一定的

f4d9748ff459480090daeae1fe86a939.png

 

public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "---" + i);
        }
        return "线程执行完毕了";
    }
}
public class Demo {
    public static void main(String[] args) {
        //优先级: 1 - 10 默认值:5
        MyCallable mc = new MyCallable();

        FutureTask<String> ft = new FutureTask<>(mc);

        Thread t1 = new Thread(ft);
        t1.setName("飞机");
        t1.setPriority(10);
        //System.out.println(t1.getPriority());//5
        t1.start();

        MyCallable mc2 = new MyCallable();

        FutureTask<String> ft2 = new FutureTask<>(mc2);

        Thread t2 = new Thread(ft2);
        t2.setName("坦克");
        t2.setPriority(1);
        //System.out.println(t2.getPriority());//5
        t2.start();
    }
}

守护线程

  • 用户线程和守护线程

    我们自己写的线程就叫做用户线程,当给这个线程通过setDaemon设置成true之后,用户线程就变成了守护线程。

    守护线程的特点: 当用户线程都执行完成之后,守护线程就没有执行的必要了。

  • 相关方法

3a8e9a09b8584e4cab02abaf6d308922.png

public class MyThread1 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(getName() + "---" + i);
        }
    }
}
public class MyThread2 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName() + "---" + i);
        }
    }
}
public class Demo {
    public static void main(String[] args) {
        MyThread1 t1 = new MyThread1();
        MyThread2 t2 = new MyThread2();

        t1.setName("女神");
        t2.setName("备胎");

        //把第二个线程设置为守护线程
        //当普通线程执行完之后,那么守护线程也没有继续运行下去的必要了.
        t2.setDaemon(true);

        t1.start();
        t2.start();
    }
}

 

 

 

 

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

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

相关文章

echers配置项:X轴,Y轴颜色修改

如上图绿框所示&#xff0c;修改x&#xff0c;y轴的颜色 let option {xAxis: {axisLine:{lineStyle:{color:red}},},yAxis: {type: value,axisLine:{lineStyle:{color:red}},}, }

胎压模块对贴片晶振的要求

在没有胎压监测的时代&#xff0c;有数据统计得出&#xff0c;在高速公路发生的事故中&#xff0c;由轮胎故障引发的占了46%&#xff0c;其中爆胎就占了70%以上&#xff0c;事故风险频有发生。且轮胎在爆炸中所产生的的冲击波&#xff0c;足以把人炸开至1米开外&#xff0c;在这…

sqlserver正确配置

一、启动sql server 服务&#xff0c;右键–>启动 二、设置网络协议 三、启动sa用户 1.使用windows用户验证登录Studio工具 2.选择安全性–>登录名–>sa, 右键选择属性 3.设置服务器身份验证模式 4.导入数据库文件

【小项目】简单实现博客系统(一)(前后端结合)

一、实现逻辑 1&#xff09;实现博客列表页 让页面从服务器拿到博客数据&#xff08;数据库&#xff09; 2&#xff09;实现博客详情页 点击博客的时候&#xff0c;可以从服务器拿到博客的完整数据 3&#xff09;实现登录功能&#xff08;跟之前写的登录页面逻辑一致&…

OpenCompass大模型离线测评

一、目录 环境配置环境测试本地模型测评 二、实现 环境配置 >>创建环境 conda create --name opencompass python3.10 pytorch torchvision pytorch-cuda -c nvidia -c pytorch -ysource activate opencompass git clone https://github.com/open-compass/opencompas…

Ollama:本地大模型运行指南

Ollama 简介 Ollama 是一个基于 Go 语言开发的可以本地运行大模型的开源框架。 官网&#xff1a;ollama.com/ GitHub 地址&#xff1a;github.com/ollama/olla… Ollama 安装 下载安装 Ollama 在 Ollama 官网根据操作系统类型选择对应的安装包&#xff0c;这里选择 macOS…

带插画的登录页火爆一时,不过好像有点过气了,是么?

插画在B端登录页中的作用是通过增加视觉吸引力、塑造品牌形象、提升用户体验和增加可视化指引等方式&#xff0c;为用户提供一个愉悦、易用、具有个性化的登录体验。这有助于提高用户对企业或组织的认知和好感度&#xff0c;增加用户的参与度和忠诚度。 当年这种分割很火爆呀&…

npm install [Error]

npm install 依赖的时候报错 依赖版本问题的冲突&#xff0c;忽视即可 使用 npm install --legacy-peer-deps

基于MCAL的S32K312 SPI使用

本文参考“大胡子喵喵猪”大佬《S32K312配置SPI&#xff08;基于MCAL&#xff09;》https://blog.csdn.net/m0_64944741/article/details/134930744 0、简介 相比于参考文章&#xff0c;本文基于S32K312 介绍SPI的使用&#xff0c;主要是记录开发流程&#xff0c;本文基于《基…

后端之路第一站——Maven

前提&#xff1a;得会基础java 前言&#xff1a;不知道出于什么原因&#xff0c;可能是喜欢犯贱吧&#xff0c;本人从大一到大二都一直在专研前端开发&#xff0c;一点也没接触过后端&#xff0c;但是突然抽风想学后端了&#xff0c;想试着自己全栈搞一下项目&#xff0c;于是在…

邮件API接口的优势有哪些?如何有效整合?

邮件API怎么选&#xff1f;SendCloud与AokSend的性能对比分析&#xff1f; 邮件API接口作为企业与用户沟通的重要桥梁&#xff0c;其重要性不言而喻。Aok将深入探讨邮件API接口的优势、有效整合的方法、选择标准以及SendCloud与AokSend两款邮件发送服务的性能对比分析。 邮件…

【全开源】场地预定小程序支持微信小程序+微信公众号+H5

XYvenue是基于FastAdminUniApp开发的多场馆场地预定小程序&#xff0c;提供运动场馆运营解决方案&#xff0c;适用于体育馆、羽毛球馆、兵乒球馆、篮球馆、网球馆等场馆。 功能特性 1、场馆管理 可添加多个预约场馆&#xff0c;小程序端切换场馆显示。 2、场地管理 可添加多…

无线领夹麦克风怎么挑选?多款高性价比无线领夹麦克风推荐

说到领夹麦克风&#xff0c;可能有些朋友对这个名字感觉很陌生&#xff0c;但是对于互联网从业者以及短视频创作者应该会对这个名字比较熟悉。如果你是打算成为短视频创作者或者参与拍摄直播等项目&#xff0c;那这个设备就很有必要去了解甚至使用到。 因为想要拍摄出来的视频作…

企业或者个体户为什么会经营异常?

在复杂多变的市场经济环境中&#xff0c;无论是企业还是个体工商户&#xff0c;都可能遭遇经营异常的情况。及时识别这些预警信号并采取有效措施&#xff0c;对于避免潜在风险、保持健康发展至关重要。本文将深入探讨企业与个体户常见的经营异常类型、识别方法以及应对策略&…

【亚马逊云】注册APN账号及报考AWS认证考试说明演示

文章目录 1. 登录AWS网站2. 注册APN账号3. 更改APN账号密码&#xff08;选&#xff09;4. 修改APN账号信息&#xff08;选&#xff09;5. 查看AWS认证情况&#xff08;选&#xff09;6. AWS认证考试报名流程7. 修改报名控制台语言版本&#xff08;选&#xff09;8. 开始报名AWS…

使用Python处理Excel数据:去除列中的双引号

目录 引言 技术背景 步骤概述 代码示例 案例分析 扩展内容 1. 处理多个列中的双引号 2. 处理大型Excel文件 3. 自定义函数处理数据 4. 错误处理和日志记录 结论 引言 在当今信息爆炸的时代&#xff0c;数据已经成为了各个行业最宝贵的资源之一。而Excel&#xff0c…

百度Comate插件领50京东E卡

给你分享一个AI编码助手——百度Comate&#xff01;扫码参与抽红包活动&#xff0c;520宠粉&#xff01;送京东卡&#xff01;https://url.xffjs.com/sMsP7m 流程如下 点击&#xff1a;点我传送 验证码登录账户 点击个人中心 复制License 去idea或者vscode安装插件 询问一…

亚马逊调整退货处理费,卖家如何应对新挑战?

在电子商务领域&#xff0c;退货处理一直是一个重要且复杂的问题。作为全球最大的电子商务平台之一&#xff0c;亚马逊一直在寻求优化退货处理流程&#xff0c;以平衡消费者满意度和运营成本。近日&#xff0c;亚马逊宣布自2024年6月1日起&#xff0c;将对退货处理费收取标准进…

VC++6.0 ListViewReport报表使用例子

操作步骤&#xff1a; 1&#xff0c;拖一个ListContorl控件 2&#xff0c;修改ID名称 3&#xff0c;设置Report样式 3&#xff0c;加入初始化代码 void CDuplicatefilesclearDlg::InitlizationListView() {CListCtrl *lstVew (CListCtrl*)GetDlgItem(IDC_LIST_Main);lstVew-&…

RabbitMQ的基本组件有哪些?

RabbitMQ的基本组件有哪些&#xff1f; RabbitMQ介绍、解耦、提速、削峰、分发 详解、RabbitMQ安装 可视化界面讲解 RabbitMQ 不生产消息&#xff0c;他是消息的搬运工。 1. Producer: 消息的发布者。 2. Connection:producer/comsumer 和 Message Broker 之间的 TCP 连接。 3…