一、粗略理解
线程:线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
进程:进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
举个栗子粗略理解一下:
单个线程:一只小松鼠
多个线程:好多只小松鼠
单个进程:一个坚果车间
多个进程:好多个坚果车间
线程与进程的关系:一个坚果车间有好多只小松鼠在打工
二、进程
2.1基础概念
1、进程:是指⼀个内存中运⾏的应⽤程序,每个进程都有⼀个独⽴的内存空间,⼀个应⽤程序可以同时运⾏多个进程;
2、进程也是程序的⼀次执⾏过程,是系统运⾏程序的基本单位;系统运⾏⼀个程序即是 ⼀个进程从创建、运⾏到消亡的过程。
2.2特点
- 并发性:在同一时间段内,多个进程可以并发执行。
- 异步性:在多个进程并发执行过程中,进程之间互不干扰。
- 动态性:一个进程是一个程序的一次执行过程。
- 独立性:每个进程拥有一块独立的内存空间。
三、线程
3.1基本概念
1、线程:线程是进程中的⼀个执⾏单元,负责当前进程中程序的执⾏,⼀个进程中⾄少有⼀个线程。⼀个进程中是可以有多个线程的,这个应⽤程序也可以称之为多线程程序。
2、线程是进程的组成部分,它代表了一条顺序的执行流
3、在分时系统中,进程中的每个线程都拥有一个时间片,时间片结束时保存 CPU 及寄存器中的线程上下文并交出 CPU,完成一次线程间切换。当然,当进程的 CPU 时间使用结束时,所有的线程必然被阻塞。
3.2线程调度
- 分时调度:所有线程轮流使⽤ CPU 的使⽤权,平均分配每个线程占⽤ CPU 的时间。(Windows里可以通过任务管理器,选择线程,右键,设置其优先级)
- 抢占式调度:优先让优先级⾼的线程使⽤ CPU,如果线程的优先级相同,那么会随机选择⼀个(线程随机性), Java使⽤的为抢占式调度。
3.3线程的生命周期
- **新建状态:**指的是线程已经被创建,但是还不允许分配 CPU 执行。
- 就绪状态: 指的是线程可以分配 CPU 执行。在这种状态下,真正的操作系统线程已经被成功创建了,所以可以分配 CPU 执行。
- **运行状态:**当有空闲的 CPU 时,操作系统会将其分配给一个处于可运行状态的线程,被分配到 CPU 的线程的状态就转换成了运行状态。
- **阻塞状态:**运行状态的线程如果调用一个阻塞的 API(例如以阻塞方式读文件)或者等待某个事件(例如键盘输出Scanner方法调用),那么线程的状态就会转换到阻塞状态,同时释放 CPU 使用权,阻塞状态的线程永远没有机会获得 CPU 使用权。当等待的事件出现了,阻塞状态结束,线程就会从阻塞状态转换到就绪状态,重新抢到CPU时间片!
- 阻塞原因解除
- I/O设备空闲
- 网络资源到达
- sleep时间到了
- 进入阻塞的原因
- 等待I/O
- 等待网络资源
- sleep()
- 其他线程调用join,当前线程阻塞
- wait
- 阻塞原因解除
- **死亡状态:**线程执行完或者出现异常就会进入死亡状态,死亡状态的线程不会切换到其他任何状态,进入死亡状态也就意味着线程的生命周期结束了。通常线程死亡的方式有三种:
- run()方法执行完成,线程正常结束。
- 线程抛出一个未捕获的Exception或Error。
- 直接调用该线程的stop()方法来结束该线程——该方法容易导致死锁,通常不推荐使用。
3.4多线程
3.3.1基础概念
1、概念:一个进程中有多个线程
2、优点:
- 为了更好的利用cpu的资源,如果只有一个线程,则第二个任务必须等到第一个任务结束后才能进行,如果使用多线程则在主线程执行任务的同时可以执行其他任务,而不需要等待;
- 进程之间不能共享数据,线程可以;
- 系统创建进程需要为该进程重新分配系统资源,创建线程代价比较小;
- Java语言内置了多线程功能支持,简化了java多线程编程。
3.3.2并发与并行
- 并发:指一个处理器同时处理多个任务使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。所以并发是轮流处理多个任务。
- 并发是逻辑上的同时发生
- 并发是逻辑上的同时发生
- 并行:指在同一时刻,有多条指令在多个处理器上同时执行。所以并行是同时处理多个任务
- 并行是物理上的同时发生
这两种从结果上看可能是同时处理完事务,但中间的过程是有差别的
- 并行是物理上的同时发生
3.3.多线程存在的内存问题
- 竞态条件
- 当多个线程同时访问并修改同一个对象,该对象最终的值往往不如预期。
例如:创建了 100 个线程,每个线程启动时随机 sleep 一会,然后为 count 加一,按照一般的顺序执行流,count 的值会是 100。但是无论你运行多少遍,结果都不尽相同,等于 100 的概率非常低。这就是并发,原因也很简单,count++ 这个操作它不是一条指令可以做的。它分为三个步骤,读取 count 的值,自增一,写回变量 count 中。多线程之间互相不知道彼此,都在执行这三个步骤,所以某个线程当前读到的数据值可能早已不是最新的了,结果自然不尽如期望。
- 内存可见性
- 某些情况下,线程对于一些资源变量的修改并不会立马刷新到内存中,而是暂时存放在缓存,寄存器中。这导致的最直接的问题就是,对共享变量的修改,另一个线程看不到。
参考:
1、https://blog.csdn.net/weixin_51182368/article/details/125799573
2、https://www.cnblogs.com/yangming1996/p/9503911.html
3、https://www.cnblogs.com/lingstar/p/16529674.html