线程与进程
进程
操作系统的出现使得计算机每次能够运行多个程序,并且不同的程序都在单独的进程中运行。操作系统为各个独立执行的进程分配各种资源,包括内存,文件句柄以及安全证书等。 不同的进程之间可以通过一些粗粒度的通信机制来交换数据,例如套接字,共享内存,文件等。
之所以加入进程来实现多个程序的同时执行,主要基于:资源利用率,公平性和便利性。这些原因也同时催生着线程的出现。
线程
线程允许在同一个进程中同时存在多个程序控制流,通常每一个任务称为一个线程。线程会共享进程范围内的资源,比如内存句柄,文件句柄。但是每个线程有各自的程序计数器,栈以及局部变量等。线程还提供了一种直观的分解模式来充分利用多处理器系统中的硬件并行性,而在同一个程序中的多个线程也可以被同时调度到多个CPU上运行。 线程也可以称为轻量级进程,创建,撤销一个线程比启动一个新进程的开销要小得多。由于同一个进程中的所有线程都将共享进程的内存地址空间,因此这些线程都能访问相同的变量并且在同一个堆上分配对象,这就需要实现一种比在进程间共享数据粒度更细的数据共享机制。
线程的优势:
- 降低程序开发和维护成本
- 提升复杂应用程序的性能
- 降低代码的复杂度 例如:在GUI中,可提高用户界面灵敏度;在服务器应用程序中,可以提升资源利用率和系统吞吐率;还可以简化JVM的实现。
通过使用线程,可以将复杂并且异步的工作流进一步分解为一组简单并且同步的工作流,每个工作流在一个单独的线程中运行,并在特定的同步位置进行交互。
线程的风险:
- 安全性问题: 在没有充足同步的情况下,多个线程的执行顺序是不可预测的,甚至会产生奇怪的结果。要使多线程程序的行为可以预测,必须对共享变量的访问操作进行协同,这样才不会在线程之间发生彼此干扰。
- 活跃性问题: 活跃性关注另一个目标,即“某件正确的事情最终会发生”, 比如死锁,饥饿,活锁。
- 性能问题: 活跃性意味着某件正确的事情最终会发生,但却不够好,因为通常希望正确的事情尽快发生。比如同步机制通常会带来额外的性能开销。
线程无处不在
几乎所有的Java应用程序都是多线程的,即便在程序中没有显示的创建线程,但在框架中仍可能会创建线程,因此在这些线程中调用的代码同样必须是线程安全的。 线程安全性需求具有延伸性,因为当某个框架在程序中引入并发性时,框架本身会回调应用程序的代码,而这些代码会访问应用程序的状态,所以所有访问这些状态的代码路径都必须是线程安全的。