并发编程 - 基础

进程与线程详解:概念、关系、调度与应用
本文深入探讨了进程和线程的概念,强调进程作为资源分配单位,线程作为CPU调度单位的角色。阐述了它们之间的关系,即线程隶属于进程,一个进程可包含多个线程。并解释了多线程和多进程的执行方式。同时,讨论了线程的生命周期、上下文切换、同步与异步调用,并介绍了Java中线程的分类,如用户线程和守护线程。最后,提到了线程调度策略,包括线程优先级、睡眠、等待、让步等方法。

1.1 进程和线程的定义

  • 进程:具有一定独立功能的程序关于某个数据集合上的一次运行活动,**进程是系统进行资源分配和调度的一个独立单位.**每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1–n个线程。(进程是资源分配的最小单位)

  • 线程线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源

同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)

可以看到上面一直在强调的,进程是用来管资源的,加载资源,加载指令,管理IO;而线程是真正用来执行指令的

1.2 进程和线程的关系

一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行.
相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,并且线程拥有自己的栈空间.
一个程序至少有一个进程,一个进程至少有一个线程,同时线程不能脱离进程而单独存在

1.3 进程和线程的区别

简而言之,进程是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个线程。进程在执行过程中拥有独立的内存单元,而多个线程共享内存资源,减少切换次数,从而效率更高。

线程是进程的一个实体,是cpu调度和分派的基本单位,是比程序更小的能独立运行的基本单位。同一进程中的多个线程之间可以并发执行。

1.4 操作系统中的进程和线程

在操作系统中,以多进程形式,允许多个任务同时运行(其实是进程之间切换运行的);以多线程形式,允许单个任务分成不同的部分运行(每个部分的代码由一个线程来负责执行)。

注:可以看出来一个应用程序的代码,主要是由线程负责在内存中执行,同时这些代码可以分为不同的部分交给多个线程分别执行,在线程执行代码过程中,如果需要用到计算的机资源,那么就可以从线程所属的进程中获取,而进程则是操作系统进行资源分配和调度的独立单位。

1.5 多进程和多线程

线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。

多进程是指操作系统能同时运行多个任务(程序)。

多线程是指在同一程序中有多个顺序流在执行。

1.6 线程的应用

多线程的设计可以让方法的执行变成异步的,这样对于项目中读取文件,等长时间费事操作,如果我们不需要他的结果,可以使用多线程变成异步调用

1.7 并行和并发

**① 并行:**多个线程在一个时间点同时运行(真正的同时运行,多个cpu)
**② 并发:**在一段时间,线程轮流使用CPU

1.8 同步调用和异步调用

**同步:**阻塞在此,等待方法调用结束才能继续往下进行
**异步:**不需要等待结果的返回(使用多线程完成)

比如我们在一个项目中有一个读取大文件的操作,那就新开线程要把他变成异步的,防止阻塞其他功能

2. java中的线程

2.1 线程的分类

2.1.1 用户线程 (User Thread)

也可以称为前台线程、执行线程

2.2.2 守护线程

守护线程(即daemon thread)是指程序运行的时候在后台提供一种通用服务的线程,比如垃圾回收线程就是一个很称职的守护者,并且这种线程并不属于程序中不可或缺的部分。

因此,当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程。反过来说,只要任何非守护线程还在运行,程序就不会终止。

用户线程和守护线程两者几乎没有区别,唯一的不同之处就在于虚拟机的退出: 如果用户线程已经全部处于死亡状态,虚拟机也就退出了,这是也不用管守护线程是否还存在了

注:java中创建出来的线程默认是用户线程,但是在启动线程前可以通过特定方法(setDaemon)把该线程转为守护线程

2.2.3 "main"的线程

当我们运行一个java程序的时候,其实就是让JVM创建一个名字叫"main"的线程,然后让这个线程去执行我们所编写的类中main方法的代码。

我们可以把这个线程称之为main线程或主线程,因为这个线程是第一个执行我们编写代码的线程,但是这时候并不是只有这一个线程在JVM中

3. 创建多线程的方法以及线程的启动与停止

创建多线程的方法以及线程的启动与停止

4. 线程的声明周期

线程的生命周期

5. 什么时候会发生线程的上下文切换

  1. 线程的cpu时间片用完
  2. 垃圾回收
  3. 有更高优先级的线程需要运行
  4. 线程自己调用了sleep, yield, wait, park, synchronized, lock等方法

频繁的上下文切换会影响性能

6. 线程调度

1、调整线程优先级:Java线程有优先级,优先级高的线程会获得较多的运行机会。

Java线程的优先级用整数表示,取值范围是1~10,Thread类有以下三个静态常量:

static int MAX_PRIORITY
线程可以具有的最高优先级,取值为10。
static int MIN_PRIORITY
线程可以具有的最低优先级,取值为1。
static int NORM_PRIORITY
分配给线程的默认优先级,取值为5。

Thread类的setPriority()和getPriority()方法分别用来设置和获取线程的优先级。
每个线程都有默认的优先级。主线程的默认优先级为Thread.NORM_PRIORITY。
线程的优先级有继承关系,比如A线程中创建了B线程,那么B将和A具有相同的优先级。
JVM提供了10个线程优先级,但与常见的操作系统都不能很好的映射。如果希望程序能移植到各个操作系统中,应该仅仅使用Thread类有以下三个静态常量作为优先级,这样能保证同样的优先级采用了同样的调度方式。

2、线程睡眠: Thread.sleep(long millis)方法,使线程转到阻塞状态。millis参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,就转为就绪(Runnable)状态。sleep()平台移植性好。

3、线程等待: Object类中的wait()方法,导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 唤醒方法。这个两个唤醒方法也是Object类中的方法,行为等价于调用 wait(0) 一样。

4、线程让步: Thread.yield() 方法,暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程。(是转成就绪状态)

5、线程加入: join()方法,等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。

6、线程唤醒: Object类中的notify()方法,唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待。 直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。类似的方法还有一个notifyAll(),唤醒在此对象监视器上等待的所有线程。
注意:Thread中suspend()和resume()两个方法在JDK1.5中已经废除,不再介绍。因为有死锁倾向。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值