线程就像超市排队结账,单线程是一个收银台多人排队,多线程是多个收银台多人排队

本文旨在深入理解线程的概念,包括单线程和多线程的区别,线程的创建与启动,线程调度,线程同步以及线程安全的重要性。通过实例探讨了Java中线程的实现方式,强调了多线程在利用CPU资源和并发执行上的优势,同时也指出线程安全问题及其解决方案,如synchronized关键字的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多线程

本节课目标:

1.理解线程的概念

2.掌握线程的基本创建和启动方式

3.了解线程的几种常用方法

4.掌握线程调度的常用方法

5.掌握线程的同步

6.理解线程安全的类型

进程:它是应用程序的执行实例,它有独立的内存空间和系统资源。
应用程序的执行实例---->进程<----有独立的内存空间和系统资源
CPU调度和分派的基本单位---->线程<----进程中执行运算的最小单位,可完成一个独立的顺序控制流程

1.1.什么是多线程?

线程是CPU调度和分派的基本单位,它是进程中执行运算的最小单位,也是进程中运算的基本单位,一个线程可完成一个独立的顺序控制流程。

如果在一个进程中同时运行了多个线程,用来完成多个不同的工作,则称之为“多线程”。

多线程和单线程

单线程:如果一个程序中只有一个线程,则称为单线程。
多个线程交替占用CPU资源,而非真正的并非执行。

多线程和单线程的区别

(1)多线程在执行中并不一定有单线程执行快。
(2)多线程产生的根本原因也是他最根本的优势在于我们能够在一个程序中,同时干多件事。可以充分利用CPU资源。
(3)其实多线程有两个概念:一种是指单核CPU的多线程,一种是指多核CPU的多线程。

单核CPU:同时只能执行一个线程,但是同样可以实现多线程,这个多线程是抢占式/交替式执行的。

多核CPU:可以进行交替执行,也可以实现真正的物理上的并行执行。

1.2主线程

JAVA给我们准备了一个类,用来支持我们进行多线程编程,Thread类
java.lang.Thread类
在java中有且只有一个主线程,就是我们程序的入口main方法。

主线程
			(1)main()方法即为主线程入口
			(2)产生其他子线程的线程
			(3)必须最后完成执行,因为他执行各种关闭动作

1.3线程的基本创建和启动

创建线程的两种方式

(1)继承java.lang.Thread类
(2)实现java.lang.runnable接口

使用线程的步骤:

定义线程 -> 创建线程对象 -> 启动线程 -> 终止线程

start()和run()的区别

如果是死奥用run()方法。他只是一个普通方法,届时将只有主线程在执行此方法而已。
如果是调用该start()方法,他将会开启一个线程,然后此线程将会和其他线程交替执行某些任务,此线程执行的内容就是run()方法内的任务。

1.3.1继承Thread类

线程创建的第一种方式:

(1)定义MyThread类继承Thread类
(2)重写run()方法,编写线程执行体
(3)创建线程对象,调用start()方法启动线程

第二种方法:
(1)实现runnable接口
(2)重写run()方法
(3)创建线程对象,组装runnable接口的实现类,
如果再创建第二个线程,这时候我们同样给其启动,会发现两个线程是交替执行的,并且没有什么规律。这种叫做“CPU的抢占式调度”。

多个线程交替执行,不是真正的并行。
线程每次执行时长由分配的CPU时间长度决定

启动线程是否可以直接调用run()方法;
在这里插入图片描述
如果线程不调用start()那么不会开启线程,直接使用线程调用run()方法会是主线程去调用run()方法。那么自然不会再出现交替执行,只有这一条main线程执行路径,属于单线程执行模式。

多线程的好处:

(1)充分利用CPU的资源
(2)简化编程模型
(3)带来良好的用户体验

1.4线程的生命周期

在这里插入图片描述

1.5了解线程的几种状态

创建状态:当new Thread()时,线程处于创建状态

就绪状态:当调用了start()之后,线程处于就绪状态
运行状态:当线程被分配到CPU资源,线程处于运行状态,
如果线程运行状态时,是处于抢占执行的,当没抢到时又回到就绪状态。
死亡状态:当线程执行完任务,或者被外部干涉结束,线程会进入死亡状态
阻塞状态:当用户在输入/线程在休眠时,线程会进入阻塞状态

1.6线程的调度

1.6.1线程优先级

代码演示:
在这里插入图片描述

1.7掌握线程的同步问题(线程安全)

同时有多个线程在执行任务,虽然他们是交替执行,但是速度切换很快,如果有一些资源被共享,可能会导致资源出错。

线程并发

可以通过加锁来解决安全问题。

synchronized同步

同步方法:
public synchronized void saleticket(){
}

同步代码块:
synchronized(this){
}

线程安全类型

StringBuffer和StringBuilder
它们在使用中没有区别,但是StringBuffer是线程安全的,而StringBuilder非线程安全,效果较高。

HashMap和Hashtable
Hashtable是线程安全的

ArrayList和Vector
Vector是线程安全的

队列应用(用队列模拟超市交款处的顾客流) 使用一个队列模拟一队通过丹尼斯超市交款处的顾客流。为了创建这个模拟,我们必须模拟排队时间和顾客通过流。我们可以通过一个循环模拟时间,每通过一个顾客代表一定的时间间隔——例如,一分钟。我们可以使用一个队列模拟顾客流,队列中的一个数据项代表一位顾客。 为了完成这个模拟,我们需要知道顾客加入交款处队列的频率、交款结算服务情况和离开的频率。假设交款队列有以下属性。 • 每分钟有一个顾客完成交款并离开(假设此时至少有一个顾客等待服务)。 • 每分钟有零个到两个顾客加入,没有顾客到达的概率是50% , 一个顾客到达的概率是 25 % ,两个顾客到达的概率是 25 %。(如何模拟?) 我们可以使用下面的算法模拟一个时间段 n 分钟内的顾客流。 初始化队列为空。 for (minute = 0 ; minute < n ; + + minute) { 如果队列不空,对头顾客交款并离开(即出对); 产生一个0-3范围内的随机数k; 如果k=1,一个顾客加入交款队列(入对); 如果k=2,两个顾客加入交款队列(入对); 如果k=0或3,不增加任何顾客到交款队列; } 调用 rand ( )函数是产生伪随机数的一种简单的方法,rand函数在中。 我们的模拟程序应该在每一个模拟分钟期间内更新下列信息,即每一次通过循环。 • 完成交款服务的总顾客数 • 这些顾客花费在排队等待的时间总和 • 顾客花费在排队等待的最长时间 为了计算顾客等待的时间长度,我们需要存储“minute”,作为这个客户队列数据项的一部分,表示顾客加入的时间。 如果你使用程序模拟一列顾客流,试着完成下面的表格。请注意,平均等待时间是等待时间总和除以总的服务顾客数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值