1. 促进进程和线程出现的原因,是要解决以下问题:
- 资源利用率
- 公平性
- 便利性
2. 进程: 操作系统为各个独立执行的进程分配各种资源,包括内存,文件句柄以及安全证书等。进程之间可以通过一些粗粒度的通信机制来交换数据,包括:套接字,信号处理器,共享内 存,信号量以及文件等。
3. 线程:线程允许在同一个进程中同时存在多个程序控制流。线程会共享进程范围内的资源,例如内存句柄和文件句柄,但每个线程都有各自的程序计数器,栈以及局部变量等。线程也被称为 轻量级的进程,在大多数现代操作系统中,都是以线程为基本的调度单位。
4. 线程的优势
- 可以发挥多处理器的强大能力:多线程程序可以通过提高处理器资源利用率来提升系统吞吐率。
- 建模的简单性:比如在编写Servlet中,不需要了解有多少请求在同一时刻要被处理,套接字的输入输出流是否被阻塞等问题。
- 异步事件的简化处理:比如可以利用多线程把复杂的非阻塞I/O,转变为同步I/O,即每个请求都拥有自己的处理线程。
- 响应更灵敏的用户界面:在AWT和Swing等工具中,采用一个事件分发线程来替代主事件循环。
5.线程带来的风险
- 安全性问题:比如竞态条件。
- 活跃性问题:比如死锁,饥饿,活锁。
- 性能问题:线程调度是个极大开销的操作;多个线程共享数据时,必须使用同步机制,而这些机制往往会抑制某些编译器的优化。
6.解决多个线程访问一个可变的状态变量导致出现错误的三种方式
- 不在线程之间共享该状态变量
- 将状态变量修改为不可变的变量
- 在访问状态变量时使用同步
7.线程安全性
当多个线程访问某个类时,不管运行环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。 其中正确性的含义是,某个类的行为与其规范完全一致。在良好的规范中通常会定义各种不变性条件来约束对象的状态,以及定义各种后验条件来描述对象操作的结果。
8.竞态条件
当某个计算的正确性取决于多个线程的交替执行时序时,那么就会发生竞态条件。
“先检查后执行”是一种常见的竞态条件,它的本质是基于一种可能失效的观察结果来做出判断或者执行某个计算。下面的代码LazyInitRace中就包含一个竞态条件,它可能会破坏这个类的正确性。
public class LazyInitRace { private ExpensiveObject instance = null; public ExpensiveObject getInstance() { if (instance == null) { instance = new ExpensiveObject(); } return instance; } }
9.内置锁
java提供了一种内置的锁机制来支持原子性:同步代码块。它包括两部分:一个作为锁的对象引用,一个作为由这个锁保护的代码块。每个Java对象都可以用做一个实现同步的锁,这些锁被称为内置锁或监视锁。线程在进入同步代码块之前会自动获得锁,并且在退出同步代码块时自动释放锁,而无论是通过正常的控制路径退出,还是通过从代码块中抛出异常退出。获得内置锁的唯一途径就是进入由这个锁保护的同步代码块或方法。
- java的内置锁是互斥锁:这意味着最多只有一个线程能持有这种锁。
- java的内置锁是可以重入的:即某个线程试图获得一个已经由它自己持有的锁,那么这个请求就会成功。