本次视频讲解了以下几个问题:
一、线程实现模型
用户态创建的模型与 操作系统的内核态模型对应关系
- 一对一 : java操作模型就是一对一,当我们使用new thread的时候就是创建了一个用户态模型,同时会在操作系统中创建一个内核态。优点是当用户态阻塞导致对应的内核态阻塞。但是不会影响其他线程的执行,同时在用户态阻塞后,会暂时挂起,这时候,将会转换为内核态挂起。这个转换很是消耗资源。这也是缺点之一。
- 多对一 : 多个用户态 对应一个内核态。这样一个用户态阻塞导致内核阻塞。然后与此内核态对应的用户态将都阻塞。优点是不需要转换
- 多对多: 以上两种的结合。
二、jvm 内存模型 与 机器硬件的模型
1> jvm
包括两部分: 堆和 栈
———————————-
栈1 栈2 栈3 —- 栈n
堆<br />-----------------------
- 栈中的数据是每个线程存储自己的局部变量的
- 堆中存储的是共享变量
2> 机器硬件内存模型:
① cpu
② 寄存器
③ cach环城
④ 内存
速度:1》2》3》4
大小:4》3》2》1
三、数据可见性问题
由于java 的内存模型的特点。导致了数据可见性问题
因为: 数据在 读取与写入的顺序如下
读取:系统会 检查寄存器中是否存在 然后检查 缓存中是否存在 最后在检查 内存中。所以有三个位置存储值。这样在数据变更时候 例如 : a 从 1 => 2,系统会暂时将值2 放在缓存中 , 这时候另外一个线程来读取的时候读到值将会是 1 。因为内存 与 线程2 的 缓存和寄存器中的值是没有来得及改变 。
所以导致了 数据的错误。
另外问题: 由于指令重排,也会导致 内存值在没有变化时候后就会被其他线程使用,然而这个值其实应该已经被线程1 改变了才对。
解决这个问题:可以是volatile 关键字。。
- 这个修饰符的作用是: 将读取数据 时候 直接读取内存数据,和 写入时候直接写入内存。这样在使用时候将会避免数据的可见性问题。同时这个关键字也会 干涉指令重排机制,使得,先操作后读取 为宗旨的执行,也就是 happen-before 原则。
- 另外也可以使用 synchrnized 关键字。
被此关键字修饰的代码块,将会是原子性操作。并且内部的所有变量都将会有 volatile 特性。既:直接操作内存进行 读或者写,所以有性能上的损失。
三、 java 线程的 user 线程与 deam 线程 ,用户线程与守护线程
- 用户线程 执行完毕后,守护线程会自动停止。
- 主线程结束后,用户线程(另起的用户线程)会指继续执行,直到完成。主线程不会影响 其他的用户线程
- 学习到的命令: jsp 查看所有线程
- jstack 线程编号 : 查看线程的详细内容
(找时间去查找 ps 与 jstack 命令的用法)
以上是第二课的大概内容。。。
