线程和进程
进程
进程是处于运行中的程序,是系统进行资源分配的调度的独立单位。
进程特点:
-
独立性:进程是系统中独立存在的实体,它可以拥有自己独立的资源,每个进程都有自己私有的地址空间。
- 动态性:进程和程序的区别就是进程是正在系统中活动的指令集合。
- 并发性:多个进程可在单个处理器上并发进行,进程之间不会相互影响。
线程
线程是进程的组成部分,一个进程可以有多个线程,一个线程必须有一个父进程。线程使得同一个进程可一并发处理多个任务。线程可以拥有自己的程序计数器、自己的堆栈和自己的局部变量,但不拥有系统资源,它与进程中的其他线程共享进程所拥有的所有资源。线程是处理器调度的基本单位。
线程特点:
- 线程可与其他线程共享进程中的共享变量和部分环境,相互之间协作来完成进程的任务。
- 线程是独立运行的,它并不知道系统中还有其他线程存在。
- 线程的执行是抢占式的。
- 线程的调度和管理由进程本身负责,操作系统不参与。
总结:操作系统可以同时执行多个任务,每个任务就是进程;进程可以同时执行多个任务,每个任务就是线程。
线程相对于进程的优势:
- 进程之间不能共享内存,但线程之间共享内存非常容易。
- 系统创建一个进程必须分配独立的内存空间和相关资源,但创建线程代价要小得多,因此多线程实现多任务效率更高。
- Java语言内置了多线程功能支持,简化了Java的多线程编程。
并发和并行的区别:并行是指在同一时刻,有多条指令在多个处理器上运行;并发是在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。
线程问题
1、安全性问题
安全性的含义是“永远不发生糟糕的事情”。
线程安全问题主要和同步有关。在没有做好同步的情况下,多个线程中的操作顺序是不可预测的,结果的正确性无法保证。
竞态条件(Race Condition):计算的正确性取决于多个线程的交替执行时序时,就会发生竞态条件。最典型的就是“先检测后执行”,比如延迟实例化(单例模式是最典型的延迟实例化)。
2、活跃性问题
活跃性关注的是“某件正确的事情最终会发生”。当某个操作无法继续进行下去时,就会发生活跃性问题。
在串行程序中,活跃性问题的形式之一就是无限循环。而在线程中,活跃性问题还包括:死锁、饥饿和活锁。
3、性能问题
性能问题包括多个方面:服务时间过长、响应不灵敏、吞吐率过低、资源消耗过高、可伸缩性较低等。
在多线程程序中,当线程切换时,就会出现上下文切换操作,如果线程之间切换频繁,这种操作将带来极大的开销:保存和恢复执行上下文、丢失局部性、CPU时间更多的花在线程调度而不是线程执行上。但线程共享数据时,必须使用同步机制,而这些机制往往会抑制某些编译器优化,使内存缓存区中的数据无效,以及增加共享内存总线的同步流量。这些因素都将带来额外的性能开销。
线程安全性
线程安全的定义:当多个线程访问某个类时,不管运行时采用何种调度或者这些线程之间如何交替执行,并且在主调代码中不需要任何同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。
线程安全的核心是对状态访问操作进行管理,特别是对共享和可变的状态的访问。一个对象是否需要实现线程安全,取决于该对象是否会被多个线程访问(这里指程序中访问该对象的方式,而不是该对象内部要实现的功能)。要使得对象是线程安全的,需要采用同步机制协同对对象可变状态的访问,Java中的同步机制包括:sunchronized关键字、volatile类型的变量、显示锁Lock、原子变量等。