线程与进程
线程
线程是处理器任务调度和执行的基本单位。每个线程有自己的程序计数器、虚拟机栈 和 本地方法栈。
程序计数
程序计数器主要有下面两个作用:
1.字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。
2.在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。
程序计数器私有主要是为了线程切换后能恢复到正确的执行位置。
虚拟机栈
每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
本地方法栈
本地方法栈:和虚拟机栈所发挥的作用非常相似,区别是: 虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。 在 HotSpot 虚拟机中和 Java 虚拟机栈合二为一。
虚拟机栈与本地方法栈都是为了保证线程中的局部变量不被别的线程访问到
线程创建方式
(1)继承 Tread 类
(2)实现 Runnable 接口
一个是接口一个是实现类,常用接口可以避免单继承的局限性外,还有(不能换行好难受呐)继承Thread类的方式可能会导致类的局部变量不能正确的被共享。因为每个线程都是一个独立的对象,它们之间不能共享实例变量,如果需要共享变量,就必须使用静态变量或共享对象锁。而使用Runnable接口的方式,多个线程可以共享同一个Runnable实例,从而共享实例变量。
线程池:
线程池是一种利用池化技术思想来实现的线程管理技术,主要是为了复用线程、便利地管理线程和任务、并将线程的创建和任务的执行解耦开来。我们可以创建线程池来复用已经创建的线程来降低频繁创建和销毁线程所带来的资源消耗。在JAVA中主要是使用ThreadPoolExecutor类来创建线程池
线程池的优点:
降低资源消耗,复用已创建的线程来降低创建和销毁线程的消耗。
提高响应速度,任务到达时,可以不需要等待线程的创建立即执行。
提高线程的可管理性,使用线程池能够统一的分配、调优和监控。
进程
进程是操作系统资源分配的基本单位,**进程是由进程控制块、程序段、数据段三部分组成;**进程控制块是进程存在的惟一标识,系统通过PCB的存在而感知进程的存在
进程的三种基本状态:
- 就绪状态
- 运行状态
- 阻塞状态
进程与线程的区别:
根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位
资源开销:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。
包含关系:如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
内存分配:同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的
影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。
执行过程:每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行
死锁
- 互斥条件:同一资源同时只能由一个线程读取
- 不可抢占条件:不能强行剥夺线程占有的资源
- 请求和保持条件:请求其他资源的同时对自己手中的资源保持不放 循环等待条件:
- 在相互等待资源的过程中,形成一个闭环
想要预防死锁,只需要破坏其中一个条件即可
避免死锁
各种死锁防止方法能够防止发生死锁,但必然会降低系统并发性,导致低效的资源利用率。
在程序运行时避免发生死锁。
银行家算法:
第二列 Has 表示已拥有的资源数,第三列 Max 表示总共需要的资源数,Free 表示还有可以使用的资源数。从图 a 开始出发,先让 B 拥有所需的所有资源(图 b),运行结束后释放 B,此时 Free 变为 5(图 c);接着以同样的方式运行 C 和 A,使得所有进程都能成功运行,因此可以称图 a 所示的状态时安全的。
死锁的检测与恢复
检测:类似于银行家算法,检查每个进程是否处于安全状态
恢复:
- 「资源剥夺法」。通过内存调度将死锁进程转移至外存中挂起,抢占其资源,并将这些资源分配给其他的死锁进程。
- 「撤销进程法(或终止进程法)」。强制杀死该进程,剥夺这些进程的资源。虽然实现简单,但是付出的代价可能会很大,部分进程很可能运行了很长时间,但是被杀之后,功亏一篑。
- 「进程回退法」。让一个或者多个死锁进程回退到足以避免死锁的地步。这要求系统要记录进程的历史信息,设置还原点。