JMM(Java Memory Model)是JVM定义的内存模型,用来屏蔽各种硬件和操作系统的内存访问差异。
其中read和load,store和write必须成对使用,顺序但补一定连续的执行。通俗的说,就是执行了read,后面一定会执行load,但不一定read之后立马load;store和write也一样。lock和unlock也是成对出现,一个变量在同一时间点只能有一个线程对其进行lock。
对于普通变量的操作: 创建变量,是在主内存中初始化。 线程用到的变量,会先从主内存中拷贝( read
)出来,加载( load
)到工作内存,然后引用( use
)变量并运算赋值( assign
)。然后存储( store
)到工作内存,然后更新( write
)掉原来的变量。
普通变量的值在线程间传递均需要通过主内存来完成。例如,线程A修改一个普通变量的值,然后向主内存进行回写,另外一条线程B在线程A回写完成了之后再从主内存进行读取操作,新变量值才会对线程B可见。
对于 volatile
修饰的变量:过程和普通变量一样。但保证变量对所有线程的可见性,并且会禁止指令重排序的优化。
volatile的特殊规则保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。因此,可以说volatile保证了多线程操作时变量的可见性,而普通变量则不能保证这一点。
它是判断数据是否存在竞争、线程是否安全的主要依据,依靠这个原则,我们可以通过几条规则一揽子地解决并发环境下两个操作之间是否可能存在冲突的所有问题。
先行发生是Java内存模型中定义的两项操作之间的偏序关系,如果说操作A先行发生于操作B,其实就是说在发生操作B之前,操作A产生的影响能被操作B观察到,“影响”包括修改了内存中共享变量的值、发送了消息、调用了方法等。
线程是比进程更轻量级的调度执行单位,线程的引入,可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源(内存地址、文件I/O等),又可以独立调度(线程是CPU调度的基本单位)。
1:N
N:M
的关系,这种就是多对多的线程模型。 Java线程实现:JDK1.2之前是用户线程,1.2和之后的版本,使用操作系统原生线程模型(内核线程)。
线程调度是指系统为线程分配处理器使用权的过程,主要调度方式有两种:
Thread.yield()
可以让出执行时间,但是要获取执行时间的话,线程本身是没有什么办法的)。在这种实现线程调度的方式下,线程的执行时间是系统可控的,也不会有一个线程导致整个进程阻塞的问题,Java使用的线程调度方式就是抢占式调度 。 虽然Java线程调度是系统自动完成的,但是我们还是可以“建议”系统给某些线程多分配一点执行时间,另外的线程少分配一点——通过设置线程优先级的方式(两个线程同时处于Ready状态时,优先级越高的线程越容易被系统选择执行),不过这方法不是很可靠,因为系统线程优先级和Java的10种线程优先级不一定一一对应。