基本概念
程序、进程、线程之间的概念
程序是静态的概念windows下通常指exe 文件 linux 下 java 的 jar war 文件
进程是动态的概念,是程序的运行状态,进程说明程序在内存中的边界
线程是进程内的一个"基本任务",每个线程都有自己的功能,即一个功能事件,是CPU分配任务与调度的基本单位
并发与并行
并发表示同一时间做的事情来回交替
并行代表真正从物理层面同时执行任务
1.jpg
以上每一个箭头,实线A任务 虚线B任务,简称 CPU的时间片
一个CPU为并发 (一个核心)
多个CPU为并行 (多个核心)
同步和异步
2.jpg
同步与异步之间做大的区别在于一个事件任务处理完毕后同步情况下需要等待任务响应后继续处理下一任务,处于阻塞状态;异步情况下则无需等待上一任务响应状态继续执行下游任务。同步和异步在目前开发过程中有着广泛的应用,大部分业务代码几乎都属于同步业务,而AJAX为典型的异步处理,另外在netty服务、java的NIO非阻塞IO都是通过异步的理念来实现的,请求服务器端请求后通过异步事件回调通知,在这个过程中就是同步与异步的区别。在大部分多线程情况下很多时候都属于异步的。
临界区
临界区用来表示一种公共资源与共享数据,可以被多个线程使用。
同一时间只能有一个线程访问临界区(阻塞状态),其他资源必须等待。
拿生活中的例子来说,例如办公室只有一台打印机(打印机为共享资源),打印机同一时间只能打印一张纸,小张与小王都需要打印一张纸,此时此刻,小张先获取了打印机的临界区使用权(先打印),这张纸打印不完,其他人就用不了,这就是我们生活中的临界区的例子;在我们的程序中,也存在了大量的临界区,比如说我们底层数据库在对某一条数据更新的时候,为了保证程序数据一定是有效的(例如不可以出现脏读),在更新前对当前操作开启一个锁的机制,锁只有被其中某一个用户所访问持有,在这个过程中其他用户都得等待,直到这个用户操作完毕后,下一个用户才可以对这条数据进行更新,在使用体验上来说,在用户A锁定的状态,其他用户都处于等待状态,直到用户A释放 ,后面的某一个用户才可以进行操作(就像排队),这就是临界区的概念。
死锁、饥饿、活锁
4.jpg
这里需要解释的是有关于线程活跃度的问题,这里根据锁的严重级别来看。
死锁:所谓死锁是指大家对于一个公共资源进行彼此争执又不愿意释放自己资源的时候,就产生出了死锁,看死锁配图,可以明白,十字路口为公共资源,每一辆车都想着往里钻,没有礼让,那么就拥堵在一起,形成了一个死锁的状态,这种死锁状态在目前开发中是最严重的一种情况,一旦陷入死锁,我们的相关程序都会陷入一个阻塞等待状态,在这种情况下需要怎么办呢?我们需要对线程进行有效的调度,让其中部分资源先释放出来。死锁是我们在开发过程中最难解决,也是最容易产生的一种情况。
饥饿:线程本身来说,它是有优先级的,线程对公共资源来说它的访问也有轻和重的区别,如饥饿图中,鸟妈妈每一次的食物就是公共资源,对于强壮的小鸟可能抢到多的食物,瘦弱的小鸟则是处于一个挨饿状态,假设这些小鸟是多个线程,瘦弱的小鸟则处于一个线程饥饿状态,它一直获取不到或者无法充分获取它所需要的资源,如果在程序当中出现这种情况,需要重点关注。这就是饥饿状态。
活锁:活锁状态是一个很有意思的状态,类似当某一个线程调度不太智能的时候,就会出现资源闲置,没有线程占用的情况,然而出现线程等待的状态。这就是我们在线程调度中不够智能的体现。
以上这三种锁的状态,是以严重的等级依次排序,无论上述任何一种情况出现,都会出现阻塞的情况。
线程安全
在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。
所谓线程安全与不安全就是在多用户情况下和单用户单线程的情况下任务执行结果保持一致。
线程安全三大特性
原子性
即一个操作或者多个操作,要么全部执行成功,要么就不执行。
(任务要么全做要么全部做)可见性
当多个线程访问同一个变量资源时,一个线程改变了这个变量资源的值,其他线程能够立即看得到修改的值。
有序性
如果在本线程内观察,所有的操作都是有序的,如果在一个线程观察另一个线程,所有操作都是无序的。
(以上线程安全部分后期详细描述,时间原因先简单叙述)
网友评论