【JavaEE】认识多线程(一)

news2024/9/23 5:15:33

✨哈喽,进来的小伙伴们,你们好耶!✨

🛰️🛰️系列专栏:【JavaEE】

✈️✈️本篇内容:了解多线程(初阶)

🚀🚀代码存放仓库gitee:JavaEE初阶代码存放!

⛵⛵作者简介:一名双非本科大三在读的科班Java编程小白,道阻且长,星夜启程!

接着上篇博客我们已经学习了进程的相关概念,了解到进程里面的相关重要属性,那么这篇博客呢我们要学习一个新的知识点——线程!

一、引入进程的目的

首先引入进程这个概念,是为了解决“并发编程”这样的问题。因为CPU 再往小了做,比较困难了,这是因为 CPU 进入了多核心的时代,要想进一步提高程序的执行速度,就需要充分的利用 CPU 的多核资源。
但是呢,多进程编程,已经可以解决并发编程的问题了已经可以利用起来 cpu 多核资源了。

弊端:

进程太重了!(消耗资源多 & 速度慢)。
1、创建一个进程,开销比较大。
2、销毁一个进程,开销也比较大。

3、调度一个进程,开销也比较大。
说进程重,主要就是重在”资源分配/回收。

线程:

所以我们的线程也就应运而生.线程也叫做“轻量级进程"。
目的就是解决并发编程问题的前提下,让创建,销毁,调度的速度,更快一些!
轻的原因:主要是"把申请资源/释放资源"的操作给省下了。

二、多线程的优点

假设小帅开了一家工厂,他在这个工厂里买了一台机器用来生产空调,小帅发现自己的产品销量不错,于是他想加大生产力度,那可以通过什么方法来提高生产效率呢?

方案一:在这个工厂旁边再开一家工厂购买一台机器用来生产空调(多进程的解决方案)

方案二 :在原本的工厂内再购买一台机器用来生产空调(多线程的解决方案)

 那么很显然第二种解决方案更划算,场地和空间都是复用之前的,共用一套资源。

线程和进程的关系:

进程包含线程!

只有第一个线程启动的时候,开销是比较大的.后续线程就省事了个进程可以包含一个线程,也可以包含多个线程.(不能没有)。你线程1 new 的对象在线程2,3,4 里都可以直接使用。线程1 打开的文在线程2,3,4 里都可以直接使用。
同一个进程里的多个线程之间,共用了进程的同一份资源(主要指的是 内存 和 文件描述符表)。
注:操作系统,实际调度的时候是以线程为单位进行调度的.
如果每个进程有多个线程了,每个线程是独立在 CPU 上调度的。

线程是操作系统调度执行的基本单位,每个线程也都有自己的执行逻辑 (执行流)。

面试题:进程和线程之间的区别与联系。

1.进程包含线程! 一个进程里面可以有一个线程,也可以有多个线程。
2.进程线程都能解决并发编程问题场景.但是进程在频繁创建和销毁中,开销更高.线程开销更低,(线程比进程更轻量)。
3.进程是系统分配资源(内存,文件资源....) 的基本单位。线程是系统调度执行的基本单位(CPU)。
4进程之间是相互独立的各自有各自的虚拟地址空间,同一个进程内部的多个线程之间,共用同一个内存空间以及文件资源,一个进程挂了其他进程一般都没事。但是一个线程挂了,很可能把整个进程都带走!

三、第一个多线程程序

那么在Java中进行多线程编程的话如何实现呢?
在 Java 标准库中,就提供了一个 Thread 类,来表示/操作线程。
Thread 类也可以视为是 Java 标准库提供的 API。

即创建好的 Thread 实例,其实和操作系统中的线程是一一对应的关系。
操作系统,提供了一组关于线程的 API(C 语言风),Java 对于这组 API 进一步封装了一下,就成了 Thread 类。

一、Thread类的基本用法

写法一:

那么通过Thread类创建线程有很多种方法,其中最简单的就是创建子类继承自Thread,重写run()方法。

class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("hello Thread");
    }
}

注意,run()方法体中描述了这个线程内部要执行哪些代码。因为每个线程都是并发执行的.(各自执行各自的代码)因此就需要告知这个线程,你执行的代码是什么。
run 方法中的逻辑,是在新创建出来的线程中,被执行的代码,意思就是并不是我一定义这个类,一写 run 方法,线程就创建出来了,相当于领导已经把任务安排好了,我还没开始干呢!

public class demo1 {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start();
    }
}

 需要调用这里的start方法,才是真正在系统中创建了线程,才开始真正执行上面的run操作。

运行结果:


 

那么我们再写一个程序来仔细观察一下线程的执行情况,我们这里通过一个while循环来打印一个语句,通过sleep方法来控制打印的速度。

class MyThread2 extends Thread{
    @Override
    public void run() {
        while (true){
            System.out.println("hello thread!");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class demo2 {
    public static void main(String[] args) {
        Thread t = new MyThread2();
        t.start();

        while (true){
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

那么我们知道,在一个进程中,至少会有一个线程。
在一个java 进程中,也是至少会有一个调用 main 方法的线程(这个线程不是你手动搞出来的)。
自己创建的 t 线程和 自动创建的 main 线程,就是并发执行的关系(宏观上看起来是同时执行)。
此处的"并发 = 并行+并发"宏观上是区分不了并行和并发的.都取决于系统内部的调度。

看运行结果:

我们可以发现现在两个线程,都是打印一条,就休眠个1s。
当 1s 时间到了之后,系统先唤醒谁呢?
通过运行结果看起来这个顺序不是完全确定(随机的)。
每一轮,1s 时间到了之后,到底是先唤醒 main 还是 thread,这是随机的,对于操作系统来说,内部对于线程之间的调度顺序,在宏观上可以认为是随机的,即所谓的——抢占式执行!
那么对于这个随机性,会给多线程编程带来很多其他的麻烦!!

写法二:

 创建一个类,实现Runnable接口,再创建Runnable实例传给Thread实例,通过Runnable来描述任务的内容。

class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println("hello java");
    }
}
public class demo3 {
    public static void main(String[] args) {
        Thread t = new Thread(new MyRunnable());
        t.start();
    }
}

运行结果:

写法三:

也就是上面两种写法的翻版,通过一个匿名内部类来实现:

public class demo4 {
    public static void main(String[] args) {
        Thread t = new Thread(){
            @Override
            public void run() {
                System.out.println("hello javaEE");
            }
        };
        t.start();
    }
}

 * 通过匿名内部类来实现。
 * 创建一个匿名内部类,继承自Thread类。
 * 同时重写run方法。
 * 同时再new出这个匿名内部类的实例。

运行结果:


 

写法四:

 * 匿名内部类的方法2
 * new 的 Runnable,针对这个创建的匿名内部类 同时new出的Runnable实例传给Thread的构造方法。
 * 通常认为这种写法好一点 能够做到让线程和线程执行的任务,更好的进行解耦。写代码追求高内聚,低耦合。
 * Runnable 单纯的只是描述了一个任务 至于这个任务是要通过一个进程来执行,还是线程池来执行 Runnable本身并不关心。

public class demo5 {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 多线程");
            }
        });
        t.start();
    }
}

写法五:

使用lambda表达式来实现!

public class demo6 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
        System.out.println("hello Thread");
    });
        t.start();
    }
}

运行结果:

OK,以上的五种写法要能够全部掌握,大体上都是差不多的,还是需要多复习几遍就能够熟能生巧了!

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

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

相关文章

单变量微积分重点(2)

泰勒公式 用柯西定理证明 拉格朗日余项 麦克劳林展开式: 皮亚诺余项的泰勒公式: 弧长的微分 注意s(t)需要在后面证明(定积分的知识) 不定积分: 注意,不同的积分方法经常会得到不同的结果,但它们…

IDEA如何配置 Gradle 及 Gradle 安装过程(详细版)

IDEA如何配置 Gradle(详细版) 一、安装 Gradle 1、下载 Gradle 安装包 官网下载链接:https://gradle.org/releases/ 2、下载后解压 3、文件夹如图所示 二、环境变量配置 1、点击我的电脑->属性->高级系统设置->环境变量 2、新建&…

[附源码]JAVA毕业设计抗击新冠疫情专题宣传网站(系统+LW)

[附源码]JAVA毕业设计抗击新冠疫情专题宣传网站(系统LW) 目运行 环境项配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 …

JSP+MySQL绿色环境保护网站的设计于实现

环保已经是当前中国的一个基本国策,国家领导人和各地政府也制定了一系列相关的政策来号召全民积极的参加到环保事业中来,为了能够更好的响应多家的号召我们开发了本JSP:MySQL:SSH 绿色环保网站,希望更多的人能够积极的参加到环保事业中来,本网站通过环境…

华为模拟器手把手安装教程-HCIE(华为网络工程师)

一、准备工作 请各位提前准备好eNSP_Setup安装程序、VirtualBox安装程序、Wireshark-win64位安装程序和WinPcap安装程序(在wireshark安装过程中可以一起安装,也可以单独安装),获取相关安装程序文件可以联系小编哦! 二、…

【蓝桥杯】第十四届模拟赛第一期及第二期填空汇总

目录 1.A题(进制位数) 位运算符 第一期 问题描述 解析 第二期 解析 代码 2.B题(日期问题) 第一期 问题描述 解析 代码实现 执行结果 第二期 问题描述 解析 3.C题(数学问题) 第一期 问题…

windows域控上批量修改域账号密码

目录 一、查询密码过期域账号信息 (一)根据OU组织架构查询密码过期账号 (二)查询域控所有密码过期账号 (三)导出dsquery查询的信息 二、批量修改过期域账号密码 (一)根据dsque…

【YOLO系列改进NO.47】改进激活函数为GELU

文章目录前言一、解决问题二、基本原理三、​添加方法四、总结前言 作为当前先进的深度学习目标检测算法YOLOv7,已经集合了大量的trick,但是还是有提高和改进的空间,针对具体应用场景下的检测难点,可以不同的改进方法。此后的系列…

Go-Excelize API源码阅读(四十)——SetCellRichText

Go-Excelize API源码阅读(四十)——SetCellRichText 开源摘星计划(WeOpen Star) 是由腾源会 2022 年推出的全新项目,旨在为开源人提供成长激励,为开源项目提供成长支持,助力开发者更好地了解开…

Android 虚拟分区详解(二) 虚拟分区布局

文章目录0. 导读1. Android 传统 A/B 分区和动态分区布局2. Android 虚拟分区布局3. 虚拟分区的思考2.1 分区只有一套,如何实现 A/B 系统特性?2.2 部分分区还有 A/B 两套,只要一套不行吗?2.3 为什么不把所有分区都放到动态分区里&…

自动化运维工具-----Ansible

一、主流自动 1.1 Puppet Puppet 是早期的 Linux 自动化运维工具,是一种 Linux、Unix、Windows 平台的集中配置管理系统,发展至今目前已经非常成熟,可以批量管理远程服务器,模块丰富,配置复杂,基于 Ruby …

[附源码]Python计算机毕业设计Django楼盘销售管理系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

Netty系列(四):源码解读 backlog 参数作用

sun.nio.ch.ServerSocketChannelImpl#bind方法 在ServerSocketChannel接口中,有一个bind方法,这个方法的作用是将通道的套接字绑定到本地地址并配置套接字以侦听连接。即用于在套接字和本地地址之间建立关联。而一旦建立关联,套接字将保持绑…

html5期末大作业——HTML+CSS公益关爱残疾人( 6个页面)

🎉精彩专栏推荐 💭文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业: 【📚毕设项目精品实战案例 (10…

Metabase学习教程:系统管理-3

保持条理化 当用户、问题和仪表盘的数量不可避免地增加时,如何保持分析的组织性。 如果您想保持竞争力,您需要让组织中的人员访问他们需要的数据,以便做出更好的决策。然而,这种数据自主化的代价是不可避免的大量分析——这会使…

CentenOS安装使用Docker

1 先更新一下yum 执行 yum -y update 这样算完成 2 清理一下,原来可能安过的docker yum remove docker docker-common docker-selinux docker-engine 3 安装所需软件包 yum install -y yum-utils device-mapper-persistent-data lvm2 安装过的可以跳过 4 配置yum中…

Qt OpenGL 光照和键盘控制

这次教程中,我们将添加光照和键盘控制,它让程序看起来更美观。我将教大家如何使用键盘来移动场景中的对象,还会教大家在OpenGL场景中应用简单的光照,让我们的程序更加视觉效果更好且受我们控制。 程序运行时效果如下:…

java项目_第168期ssm二手车交易网站-_计算机毕业设计

java项目_第168期ssm二手车交易网站-_计算机毕业设计 【源码请到资源专栏下载】 今天分享的项目是《ssm二手车交易网站》 该项目分为2个角色,管理员和用户。 用户可以浏览前台,包含功能有: 首页、商品信息、论坛信息、新闻资讯 、留言反馈、购物车、跳转…

目的:ubuntu配置使用opengl - 初探-创建一个空窗口

目的:ubuntu配置使用openGL - 初探-创建一个空窗口 环境: 系统:Ubuntu18.04 环境:g步骤: Ubuntu下使用openGL,搭建配置环境并测试窗口 1、openGL库,需要单独安装,由于本机是vmwar…

萌新源api管理系统更新教程

前言 萌新源API管理系统旨在大家提供一个更为方便的管理api的方法,经过几个月的时间,目前已经迭代到v4.41版本 那么这篇文章呢,也是想要教一下大家怎样去更新我们最新版本的管理系统,我最近也是在研究自动化更新,但是…