其他+java内存模型与线程

 2019-12-10 16:03  阅读(942)
文章分类:Java Core

1.关于建立了一个声明为父类对象,实例化为子类对象

2.重写和重载 VS. 静态分派和动态分派

重载(overload):发生在一个类中,出现了多个具有相同名字的方法,这些方法有不同的参数列表(即参数的数量和参数类型不能完全相同)

重写(override):发生在子类和父类之间的,子类中的方法和父类定义的方法具有相同的名字,相同的参数列表和相同的返回类型

划重点:虚拟机【重载】时是通过参数的静态类型而不是实际类型决定的。

【重写】是根据参数的实际类型来确定的

3.编译阶段——看静态分派

运行阶段——看动态分派

4.java内存模型

目的:定义程序中各个变量的访问规则。即在虚拟机中将变量存到内存和从内存中取出变量

(1)所有变量都存在主内存中,

(1)每条线程还有自己的工作内存,工作内存保存了该线程使用到的变量主内存副本拷贝

assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值复制给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码之时,执行这个操作。

5.volatile

具备的两种特性:(1)保证次变量对所有线程的可见性。【可见性:当一条线建成修改了这个变量的值,新值对于其他线程来说是可以立即得知的】但是不一定线程安全。volatile变量在各个线程的工作内存中不存在一致性,但主要是因为每次使用前都先刷新,抹灭了不一致的情况。

(2)禁止指令重排序优化

适用于的场景:(1)运算结果并不依赖于变量的当前值,或者能够确保只有单一的线程修改变量的值

(2)变量不需要与其他的状态变量共同参与不变约束。

6.java内存模型对volatile变量定义的特殊规则

假设T表示一个线程,V和W分别表示两个volatile型变量,那么在进行read、load、use、assign、store和write操作时候需要满足如下规则:

1)只有当线程T变量V执行的前一个动作是load的时候,线程T才能对变量V执行use动作;并且,只有当线程T变量V执行的后一个动作是use的时候, 线程T对变量V执行load动作。【use可以认为是和load和read相关联的,变量V的load和read动作必须前后按顺序】

2)只有当线程T对变量V执行的前一个动作是assign的时候,线程T才能对变量执行store动作;并且只有当线程T对变量V执行的后一个动作是store的时候,线程T才能对变量v执行assign动作。【assign可以认为是和store和write相关联的】

3)假定动作A是线程T对变量V实施的use或者assign动作,假定动作 F是与动作A相关联的load或者store动作,假定动作P是与动作F相应的对变量V的read或write动作;类似地,假定动作B是线程T对变量W实施的use或者assign动作,假定动作 G是与动作B相关联的load或者store动作,假定动作Q是与动作Q相应的对变量V的read或write动作。如果A先于B,那么P先于Q。

7.java内存模型对原子性、可见性与有序性的实现

(1)原子性(Atomicty):保证的原子操作包括:read、load、assign、use、store、和write

(2)可见性(Visibility):当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。【java内存是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值来保证可见性|普通变量和valotile变量的区别是:valotile是保证了新值能够立即同步到主内存,以及每次使用前立即从主内存刷新】

其他市县可见性的变量:synchronized和final

同步块的可见性:对一个变量执行unlock操作之前,必须先把次变量同步回主内存,执行store和write操作。

final的可见性:final修饰的字段在构造器中一旦被初始化完成,并且构造器没有把this的引用传递出去,那么在其他线程中就能看到final字段的值。

(3)有序性(Ordering):如果在本县城内观察,所有的操作都是有序的——表现为串行的语义;如果在一个线程中观察另一个线程,所有的操作都是无序的——指令重排序和工作内存与主内存同步延迟。

8.如何判断并发环境下两个操作之间是否可能存在冲突——先行发生原则

先行发生原则:java内存模型中定义的两“项”操作之间的偏序关系,如果说操作A先行发生于操作B,其实是指操作B之前,操作A产生的影响能够被操作B观察到,”影响“包括修改可内存中共享变量的值,发送了消息、调用了方法等。

9.java内存模型中的“天然”先行发生关系

1)程序次序规则:【一个线程内】,按照代码顺序,书写在前的操作先行发生于书写在后的操作

2)管城锁定规则:一个unlock操作先行发生于后面对【同一个锁】的lock操作。

3)volatile变量规则:对【一个volatile变量】的写操作先行发生于后面对这个变量的读操作

4)线程启动规则:Thread对象的start()方法先行发生于此线程的每一个动作

5)线程终止规则:线程中的所有操作都先行发生于对此线程的终止检测。可通过Thread.join()结束

6)线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,即先检测到中断,再检测到出错

7)对象终结规则:一个对象的初始化完成(构造函数执行结束)先行发生于他的finalize()方法的开始

8)传递性:如果操作A线性发生与操作B,操作B先行发生于操作C,那么可以得出操作A先行发生于操作C的结论。

一个操作“时间上的先发生”不代表这个操作是“线性发生”。

根据先行规则判断操作间顺序性,如果都不满足以上规则,可以认为是线程不安全的。

10.线程在虚拟机中的实现

每个java.lang.Thread类的实例就代表了一个线程,Thread类中的所有关键方法都被声明为Native

方式有三:

使用内核线程实现;使用用户线程实现;使用用户线程加轻量级进程混合实现

(1)使用内核线程KLT实现

即直接由操作系统内核支持的线程,这种线程由内核来完成线程切换,内核通过操纵调度器对线程进行调度,并负责将线程的任务映射到各个处理器上。每个内核线程都可以看做是内核的一个分身。【程序使用内核线程的一种高级接口——轻量级进程LWP】

(2)使用用户线程实现

一个线程只要不是内核线程,那就可以认为是用户线程。

狭义的用户进程指的是完全建立在用户空间的线程库上,系统内核不能感知到线程的存在。这种线程和用户线程之间1:N的关系称为一对多的线程模型。

线程的创建、切换和调度都需要用户程序考虑处理。

(3)混合实现

将内核线程和用户线程一起使用的实现方式。这种混合实现下,既存在用户线程,也存在轻量级进程。用户线程还是完全建立在用户空间中,并且可以支持大规模的用户线程开发,二操作系统提供支持的轻量级进程为用户线程和内核线程之间的桥梁。

11.Java线程调度【指系统为线程分配处理器使用权的过程】

调度方式:协同式线程调度和抢占式线程调度

(1)协同式线程调度:线程的执行时间由线程本身控制。线程把自己的工作执行完了之后,主动通知系统切换到另外一个线程上去。不存在线程同步的问题,线程安全;但线程执行时间不可控制,容易堵塞。

(2)抢占式调度系统:每个线程将由系统来分配执行时间,线程的切换不由线程本身决定。线程的执行时间是系统可控的,不存在进程堵塞的问题。【Java实现的就是抢占式调度】

可以“建议“系统给某些线程多分配些时间——通过设置线程优先级

存在的问题:线程调度是由操作系统说了算,但java线程的优先级并不一定与操作系统的线程优先级一一对应。/优先级可能会由操作系统自行改变。

12.状态切换

java【进程】的五种状态:新建(New)、运行(Runnable)、无限期等待(Waiting)、限期等待(Time Waiting)、阻塞(blocked)

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> 其他+java内存模型与线程

相关推荐