Java第二十章总结

news2025/1/22 16:10:41

一、线程简介

1.什么是进程:

进程是程序的运行过程,是系统进行资源分配和调度的一个独立单位。通俗来讲,进程就是在操作系统中运行的程序,例如:电脑中运行的微信、eclipse、idea等。

2.什么是线程

线程是操作系统能够进行运算调度的最小单位。一个进程至少有一个线程,一个程序可以有多个线程。

3.多线程

如果一个程序可以同时运行多个线程,那么这个程序就是多线程的。例如看视频时程序同时进行加载图像、获取字幕和获取弹幕等。

二、线程的创建
1.继承Thread类
步骤:

(1)创建线程类,并继承Thread类
(2)重写run()方法,编写线程执行体
(3)创建线程对象,调用start()方法启动线程
示例代码如下:

public class TestThread extends Thread{
    @Override
    public void run() {
        //重写run方法线程执行体
        for (int i = 0; i < 100; i++) {
            System.out.println("testThread线程第"+i+"次执行");
        }
    }
    public static void main(String[] args) {
    	//创建线程对象
        TestThread testThread = new TestThread();
        //调用start()方法开启线程
        testThread.start();//子线程开启,和主线程交替执行
        //main线程执行一个for循换
        for (int i = 0; i < 100; i++) {
            System.out.println("main线程第"+i+"次执行");
        }
    }
}

执行结果如下图所示,testThread和main两个线程会交替执行100次。截取了部分输出结果。


2.实现Runnable接口

步骤:

(1)定义MyRunnable类实现Runnable接口
(2)实现run()方法,编写线程执行体
(3)创建Runnable接口的实现类对象
(4)创建线程对象,调用start()方法启动线程
示例代码如下:

public class TestRunnable implements Runnable{
    @Override
    public void run() {
        //重写run方法线程体
        for (int i = 0; i < 100; i++) {
            System.out.println("testRunnable线程第"+i+"次执行");
        }
    }
    public static void main(String[] args) {
        //创建Runnable接口的实现类对象
        TestRunnable testRunnable = new TestRunnable();
        //创建线程对象,通过线程对象来开启我们的线程,代理
        Thread thread = new Thread(testRunnable);
        //调用start方法,启动线程
        thread.start();//子线程开启,和主线程交替执行
		//main线程执行for循换
        for (int i = 0; i < 100; i++) {
            System.out.println("main线程第"+i+"次执行");
        }
    }
}

执行结果testThread和main两个线程会交替执行100次,和上一段程序一样。

3.实现Callable接口

步骤
(1)实现Callable接口,需要返回值类型
(2)重写call方法,需要抛出异常
(3)创建目标对象
(4)创建执行服务
(5)提交执行
(6)获取结果
(7)关闭服务
 

public class TestCallable implements Callable<Boolean> {
    //重写call方法
    @Override
    public Boolean call() {
        for (int i = 0; i < 100; i++) {
            System.out.println("testCallable线程执行了"+i);
        }
        return true;
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestCallable testCallable = new TestCallable();
        //创建执行服务
        ExecutorService service = Executors.newFixedThreadPool(1);
        //提交执行
        Future<Boolean> future = service.submit(testCallable);
        //获取结果
        Boolean result = future.get();
        //关闭服务
        service.shutdownNow();
    }
}

三、线程状态

1.线程的五种状态

(1)新建状态(New): 线程对象被创建后,就进入了新建状态。执行完
(2)就绪状态(Runnable):调用线程对象的start()方法后,该线程进入就绪状态。此时线程进入等待队列,随时可能被CPU调度执行。
(3)运行状态(Running): run方法被执行时,线程获取CPU权限进行执行,进入了运行状态。
(4)阻塞状态(Blocked): 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。 当程序运行时候,遇到了 sleep、wait、join等方法或获取同步锁失败时会进入阻塞状态。
(5)死亡状态(Dead): 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

2.线程的状态关系图:

3.线程的停止

当一个线程的run()方法执行完毕后,线程会自然终止。
JDK提供stop()、destory()方法(不推荐使用)。
建议定义一个布尔类型的变量flag作为标志位,当flag=false时,终止线程。

public class TestStop implements Runnable{
	//1.设置一个标志位
    private boolean flag = true;
    @Override
    public void run() {
        while (flag){
            System.out.println("run...Thread");
        }
    }
    //2.设置一个公开的方法停止线程,转移标志位
    public void stop(){
        this.flag = false;
    }
}

4.线程的阻塞与等待

(1)线程的休眠

调用Thread类中的sleep()方法可实现线程的休眠。
sleep方法的重载:sleep(long millis) 中可传入休眠的时间,单位为毫秒。即让当前线程休眠millis毫秒。sleep(long millis, int nanos)方法,让当前线程休眠millis毫秒+nanos纳秒。
sleep时间达到前线程进入阻塞状态(Blocked)。
sleep时间达到后线程进入就绪状态(Runnable)。
sleep可以模拟网络延时,倒计时等。
线程休眠时,不会释放锁。

(2)线程的礼让

调用Thread类中的yield()方法即可实现线程的礼让。
礼让线程,让当前正在执行的线程暂停,但不进入阻塞状态(Blocked)。在执行yield方法后, 依然还是就绪状态(Runnable)。
礼让线程实际上是放弃本次执行的机会,让CPU重新调度。当然,CPU的下次调度可能是执行了其他线程,也可能有调度了此线程。下一次调度执行哪个线程是随机的。

(3)线程的合并

调用Thread类中的join()方法实现线程的合并。
合并线程,将多条线程合并为一条。就是先执行调用join()方法的线程,待此线程执行完毕后,再执行其他线程。
在此线程先执行时,其他线程进入阻塞状态(Blocked)。

5.线程状态的观测

Thread类中的getState()方法会观测线程的状态并提供一个返回值来获取线程的状态。

四、线程同步

1.概述

(1)什么是并发?

并发:同一个对象同时被多个线程操作。

(2)为什么要进行线程同步?

在日常生活中经常会遇见并发现象。同一个对象同时被很多线程操作修改,例如:抢票软件在进行三抢票时,成千上万个用户同时进行买票操作。如果这个时候不进行线程同步处理,就会导致对对象的操作极其混乱。
生活中这种情况最好的解决办法是让大家排好队一个一个进行操作,同样的在我们的线程中也可以引入线程同步 . 线程同步其实就是一种等待机制 ,多个需要同时访问此对象的线程进入这个对象的等待池 形成队列, 等待前面线程使用完毕 , 下一个线程再使用。

2.同步方法与同步块

synchronized关键字即加锁。当一个线程操作对象时,它会拿到锁,之后如果有其他的线程要来操作该对象时,会进入阻塞状态(Blocked)。直到上一个线程操作完该对象并释放锁后,后续的线程才可以拿到锁并对该对象进行操作。
举例:在买票时,一个人先来买了票,在买票过程中其他人无法对票进行操作,必须进入排队状态。等待前一个人买完票后,后面的人才能开始买票。这种操作可以避免两个人买到重复的票。
synchronized关键字包括两种用法:synchronized方法和synchronized块。

(1)synchronized方法

在方法中加上synchronized修饰符即可实现同步方法。
弊端:方法里面需要修改的内容才需要锁,此方法锁的太多 , 浪费资源。

    

private synchronized void buy() throws InterruptedException {
       /*
       方法体
       */
    }


(2)synchronized块

synchronized (obj){
    /*
    方法体
    */
}



其中obj是需要加锁的对象。要对哪个对象进行修改操作,对哪个对象加锁即可。

3.线程的死锁

(1)死锁的概念

例如:A线程占有test1资源,B线程占有test2资源。如果此时,A线程必须要调用B占有的test2资源才能继续执行,那么A就需要进入阻塞状态,等待B线程结束后释放test2的锁才能继续执行。假如恰巧B线程此时也需要A线程占有的test1资源,那么A、B两个线程就会同时进入阻塞状态,都需要等待对方执行结束,程序就出现了卡死的现象。这种情况就成为线程的死锁。

(2)死锁的避免方法

产生死锁的四个必要条件:

互斥条件:一个资源每次只能被一个进程使用。
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
不剥夺条件 : 进程已获得的资源,在末使用完之前,不能强行剥夺。
循环等待条件 : 若干进程之间形成一种头尾相接的循环等待资源关系。

五、小结

1.run()方法和start()方法的区别:

调用start()方法开启线程; 调用run方法,属于普通的方法调用,不会开启新线程。
调用start()方法多条执行路径,主线程和子线程交替执行;调用run()方法只有主线程一条执行路径。

2.yield与sleep区别:

sleep()是先进入阻塞状态,结束后在进入就绪状态。yield()则是直接进入就绪状态。
yield()会让优先级同级或优先级更高的有更高的执行机会。
 

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

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

相关文章

目标检测——R-CNN算法解读

论文&#xff1a;Rich feature hierarchies for accurate object detection and semantic segmentation 作者&#xff1a;Ross Girshick, Jeff Donahue, Trevor Darrell, Jitendra Malik 链接&#xff1a;https://arxiv.org/abs/1311.2524 代码&#xff1a;http://www.cs.berke…

不会PS!超简单的制作产品册方法

​产品册是展示产品的重要工具&#xff0c;对于很多企业来说&#xff0c;制作一本精美的产品册是必不可少的。但是&#xff0c;对于一些不会PS的人来说&#xff0c;制作产品册可能会觉得非常困难。其实&#xff0c;制作产品册并不需要PS等专业工具&#xff0c;只需要一些简单的…

电巢直播|揭秘FCBGA先进封装基板兴力量ze

随着2022年底ChatGPT的问世&#xff0c;我们不仅见证了从互联网时代到AI应用时代的跨越&#xff0c;也迎来了一个数据流量不断攀升的新纪元。在这个以数据为核心的新时代&#xff0c;算力网络成为支撑巨大数字经济的基石&#xff0c;其背后则是对硬件性能持续提升的迫切需求。 …

重点在正负上如何描述?看CHAT有何见解

问CHAT&#xff1a;重点在正负上如何描述&#xff1f; CHAT回复&#xff1a;在描述数据的波动情况时&#xff0c;也可关注其正负方向的变化。通常有以下几种方式&#xff1a; 1. 均值&#xff08;Mean&#xff09;&#xff1a;在一众数值中&#xff0c;如果大部分数值是正值且…

【数值计算方法(黄明游)】常微分方程初值问题的数值积分法:欧拉方法(向后Euler)【理论到程序】

文章目录 一、数值积分法1. 一般步骤2. 数值方法 二、欧拉方法&#xff08;Euler Method&#xff09;1. 向前欧拉法&#xff08;前向欧拉法&#xff09;2. 向后欧拉法&#xff08;后向欧拉法&#xff09;a. 基本理论b. 算法实现 常微分方程初值问题的数值积分法是一种通过数值方…

ISCTF2023 部分wp

学一年了还在入门( web where_is_the_flag ISCTF{41631519-1c64-40f6-8dbb-27877a184e74} 圣杯战争 <?php // highlight_file(__FILE__); // error_reporting(0);class artifact{public $excalibuer;public $arrow;public function __toString(){echo "为Saber选择…

实施工程师运维工程师面试题

Linux 1.请使用命令行拉取SFTP服务器/data/20221108/123.csv 文件&#xff0c;到本机一/data/20221108目录中。 使用命令行拉取SFTP服务器文件到本机指定目录&#xff0c;可以使用sftp命令。假设SFTP服务器的IP地址为192.168.1.100&#xff0c;用户名为username&#xff0c;密…

【爬虫实战】最新python豆瓣热榜Top250

一.最终效果 豆瓣是大多数新手练习爬虫的 二.数据定位过程 对于一个目标网站&#xff0c;该如何快速判定页面上的数据来源&#xff1f;首先你需要简单web调试能力&#xff0c;对大多数开发者来说都chrome浏览器应该是不二选择&#xff0c;当然我选中的也是。F12打开调试面板&…

Vite 了解

1、vite 与 create-vite 的区别 2、vite 解决的部分问题 3、vite配置文件的细节 3.1、vite语法提示配置 3.2、环境的处理 3.3、环境变量 上图补充 使用 3.4、vite 识别&#xff0c;vue文件的原理 简单概括就是&#xff0c;我们在运行 npm润dev 的时候&#xff0c;vite 会搭起…

springboot+mysql实现就业信息管理系统

springbootmysql实现的就业信息管理系统,有普通用户和管理员两种角色,演示地址:yanshi.ym4j.com:8091 普通用户账号&#xff1a;test 密码&#xff1a;123456管理员账号&#xff1a;admin 密码&#xff1a;123456 共包含就业信息管理、就业统计、用户管理等功能。 登录 就业信…

网络通信概述

文章目录 IP地址端口号协议三要素作用 五元组协议分层OSI七层模型TCP/IP 五层模型应用层传输层网络层数据链路层物理层 封装和分用发送方 - 封装中间转发接收方 - 分用 一般认为计算机网络就是利用通信线路和通信设备将地理上分散的、具有独立功能的多个计算机系统按不同的形式…

Qt 天气预报项目

参考引用 QT开发专题-天气预报 1. JSON 数据格式 1.1 什么是 JSON JSON (JavaScript Object Notation)&#xff0c;中文名 JS 对象表示法&#xff0c;因为它和 JS 中对象的写法很类似 通常说的 JSON&#xff0c;其实就是 JSON 字符串&#xff0c;本质上是一种特殊格式的字符串…

销门!销售秘籍都在这了

很多刚进销售行业&#xff0c;或者初入职场的小白&#xff0c;肯定会有这一段迷茫/茫然期&#xff1a;为什么同事每天都有客户打电话/实地拜访呢&#xff1f; 而自己却无所事事&#xff0c;也没有客户找我&#xff0c;也不知道去哪里拜访客户。 这个阶段对于销售小白来说是很…

联想SR660 V2服务器使用默认用户登录BMC失败

新到了一台服务器&#xff0c;使用默认用户登录BMC失败 登录失败提示&#xff1a;账号或密码错误 解决方案&#xff1a; 1、重置BMC 2、新增用户 开机后在出现 ThinkServer 界面按 F1&#xff0c;进入 BIOS 界面 进入 System Settings-BMC Configuration 菜单相关&#xf…

聊聊VMware vSphere

VMware vSphere是一种虚拟化平台和云计算基础设施解决方案&#xff0c;由VMware公司开发。它为企业提供了一种强大的虚拟化和云计算管理平台&#xff0c;能够在数据中心中运行、管理和保护应用程序和数据。vSphere平台与VMware ESXi虚拟化操作系统相结合&#xff0c;提供了完整…

1992-2021年区县经过矫正的夜间灯光数据(GNLD、VIIRS)

1992-2021年区县经过矫正的夜间灯光数据&#xff08;GNLD、VIIRS&#xff09; 1、时间&#xff1a;1992-2021年3月&#xff0c;其中1992-2013年为年度数据&#xff0c;2013-2021年3月为月度数据 2、来源&#xff1a;DMSP、VIIRS 3、范围&#xff1a;区县数据 4、指标解释&a…

从零开始:PHP实现阿里云直播的简单方法!

1. 配置阿里云直播的推流地址和播放地址 使用阿里云直播功能前&#xff0c;首先需要在阿里云控制台中创建直播应用&#xff0c;然后获取推流地址和播放地址。 推流地址一般格式为&#xff1a; rtmp://{Domain}/{AppName}/{StreamName}?auth_key{AuthKey}-{Timestamp}-{Rand…

(亲测有效)解决windows11无法使用1500000波特率的问题

大家好&#xff01;我是编码小哥&#xff0c;欢迎关注&#xff0c;持续分享更多实用的编程经验和开发技巧&#xff0c;共同进步。 1、问题描述 从图1可以看出串口是正常的&#xff0c;安装的驱动是CP210xVCPInstaller_x64.exe&#xff0c;但是从图2可以看出&#xff0c;串口拒…

【刷题】DFS

DFS 递归&#xff1a; 1.判断是否失败终止 2.判断是否成功终止&#xff0c;如果成功的&#xff0c;记录一个成果 3.遍历各种选择&#xff0c;在这部分可以进行剪枝 4.在每种情况下进行DFS&#xff0c;并进行回退。 199. 二叉树的右视图 给定一个二叉树的 根节点 root&#x…

GEE 23:基于GEE实现物种分布模型之随机森林法

基于GEE实现物种分布模型之随机森林法 1.物种分布数据2.研究区绘制3.预测因子选择 1.物种分布数据 根据研究目的和需要导入物种数据&#xff1a; // Load presence data var Data ee.FeatureCollection("users/************736/Distribution"); print(Original da…