[b]JAVA内存模型:[/b]
不同的平台,内存模型是不一样的,但是jvm的内存模型规范是统一的。其实java的多线程并发问题最终都会反映在java的内存模型上,所谓线程安全无非是要控制多个线程对某个资源的有序访问或修改。总结java的内存模型,要解决两个主要的问题:可见性和有序性。我们都知道计算机有高速缓存的存在,处理器并不是每次处理数据都是取内存的。JVM定义了自己的内存模型,屏蔽了底层平台内存管理细节,对于java开发人员,要清楚在jvm内存模型的基础上,如何解决多线程的可见性和有序性。
在并发编程中,需要处理两个关键问题:线程之间如何通信和线程之间如何同步
通信是指线程之间以何种机制来交换信息。在命令式编程中,线程之间的通信机制有两种:共享内存和消息传递
在共享内存的并发模型里,线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信。
在消息传递的并发模型里,线程之间没有公共状态,线程之间必须通过明确的发送消息来显式进行通信
同步是指程序中用于控制不同线程间操作发生相对顺序的机制。
在共享内存并发模型里,同步是显式进行的。程序员必须显式制定某个方法或某段代码需要在线程之间互斥执行。
在消息传递的并发模型里,由于消息的发送必须在消息的接收之前,因此同步是隐式进行的。
主内存和工作内存
1.所有的变量都存储在主内存中
2.每个线程都还有自己的工作内存,拥有主内存的对象的拷贝
3.线程只能操作自己的工作内存,线程间的交互只能通过主内存通讯
[img]http://dl2.iteye.com/upload/attachment/0114/1570/b2f3b759-446a-3c67-97d1-4b15ee9194a5.jpg[/img]
[b]内存间的交互操作:[/b]
8种操作的作用场景:
1.read 和load ,store和write 必须一对操作
2.不允许线程丢弃assign操作,变量在工作内存中改变后必须把变法同步回主内存
3.没有assign操作,不允许变量从工作内存同步回主内存
4.新变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化的变量(load或assign)对一个变量实时use和store之前必须先执行过assign和load操作
5.一个变量同一时刻值允许一条线程lock操作,但lock操作可以多次,执行相同数量的unlock,变量才会解锁
6.lock操作会清空工作内存副本,执行引擎使用前,需要执行load或者assign操作初始化变量的值
7.没有lock操作,就不允许unlock操作。不允许unlock另一个线程变量。
8.unlock操作前必须先store,write操作
那么,何谓[b]可见性[/b]? 多个线程之间是不能互相传递数据通信的,它们之间的沟通只能通过共享变量来进行。Java内存模型(JMM)规定了jvm有主内存,主内存是多个线程共享的。当new一个对象的时候,也是被分配在主内存中,每个线程都有自己的工作内存,工作内存存储了主存的某些对象的副本,当然线程的工作内存大小是有限制的。当线程操作某个对象时,执行顺序如下:
(1) 从主存复制变量到当前工作内存 (read and load)
(2) 执行代码,改变共享变量值 (use and assign)
(3) 用工作内存数据刷新主存相关内容 (store and write)
JVM规范定义了线程对主存的操作指令:read,load,use,assign,store,write。当一个共享变量在多个线程的工作内存中都有副本时,如果一个线程修改了这个共享变量,那么其他线程应该能够看到这个被修改后的值,这就是多线程的可见性问题。
那么,什么是[b]有序性[/b]呢 ?线程在引用变量时不能直接从主内存中引用,如果线程工作内存中没有该变量,则会从主内存中拷贝一个副本到工作内存中,这个过程为read-load,完成后线程会引用该副本。当同一线程再度引用该字段时,有可能重新从主存中获取变量副本(read-load-use),也有可能直接引用原来的副本(use),也就是说 read,load,use顺序可以由JVM实现系统决
定。
线程不能直接为主存中中字段赋值,它会将值指定给工作内存中的变量副本(assign),完成后这个变量副本会同步到主存储区(store-write),至于何时同步过去,根据JVM实现系统决定。
有该字段,则会从主内存中将该字段赋值到工作内存中,这个过程为read-load,完成后线程会引用该变量副本。
不同的平台,内存模型是不一样的,但是jvm的内存模型规范是统一的。其实java的多线程并发问题最终都会反映在java的内存模型上,所谓线程安全无非是要控制多个线程对某个资源的有序访问或修改。总结java的内存模型,要解决两个主要的问题:可见性和有序性。我们都知道计算机有高速缓存的存在,处理器并不是每次处理数据都是取内存的。JVM定义了自己的内存模型,屏蔽了底层平台内存管理细节,对于java开发人员,要清楚在jvm内存模型的基础上,如何解决多线程的可见性和有序性。
在并发编程中,需要处理两个关键问题:线程之间如何通信和线程之间如何同步
通信是指线程之间以何种机制来交换信息。在命令式编程中,线程之间的通信机制有两种:共享内存和消息传递
在共享内存的并发模型里,线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信。
在消息传递的并发模型里,线程之间没有公共状态,线程之间必须通过明确的发送消息来显式进行通信
同步是指程序中用于控制不同线程间操作发生相对顺序的机制。
在共享内存并发模型里,同步是显式进行的。程序员必须显式制定某个方法或某段代码需要在线程之间互斥执行。
在消息传递的并发模型里,由于消息的发送必须在消息的接收之前,因此同步是隐式进行的。
主内存和工作内存
1.所有的变量都存储在主内存中
2.每个线程都还有自己的工作内存,拥有主内存的对象的拷贝
3.线程只能操作自己的工作内存,线程间的交互只能通过主内存通讯
[img]http://dl2.iteye.com/upload/attachment/0114/1570/b2f3b759-446a-3c67-97d1-4b15ee9194a5.jpg[/img]
[b]内存间的交互操作:[/b]
8种操作的作用场景:
1.read 和load ,store和write 必须一对操作
2.不允许线程丢弃assign操作,变量在工作内存中改变后必须把变法同步回主内存
3.没有assign操作,不允许变量从工作内存同步回主内存
4.新变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化的变量(load或assign)对一个变量实时use和store之前必须先执行过assign和load操作
5.一个变量同一时刻值允许一条线程lock操作,但lock操作可以多次,执行相同数量的unlock,变量才会解锁
6.lock操作会清空工作内存副本,执行引擎使用前,需要执行load或者assign操作初始化变量的值
7.没有lock操作,就不允许unlock操作。不允许unlock另一个线程变量。
8.unlock操作前必须先store,write操作
那么,何谓[b]可见性[/b]? 多个线程之间是不能互相传递数据通信的,它们之间的沟通只能通过共享变量来进行。Java内存模型(JMM)规定了jvm有主内存,主内存是多个线程共享的。当new一个对象的时候,也是被分配在主内存中,每个线程都有自己的工作内存,工作内存存储了主存的某些对象的副本,当然线程的工作内存大小是有限制的。当线程操作某个对象时,执行顺序如下:
(1) 从主存复制变量到当前工作内存 (read and load)
(2) 执行代码,改变共享变量值 (use and assign)
(3) 用工作内存数据刷新主存相关内容 (store and write)
JVM规范定义了线程对主存的操作指令:read,load,use,assign,store,write。当一个共享变量在多个线程的工作内存中都有副本时,如果一个线程修改了这个共享变量,那么其他线程应该能够看到这个被修改后的值,这就是多线程的可见性问题。
那么,什么是[b]有序性[/b]呢 ?线程在引用变量时不能直接从主内存中引用,如果线程工作内存中没有该变量,则会从主内存中拷贝一个副本到工作内存中,这个过程为read-load,完成后线程会引用该副本。当同一线程再度引用该字段时,有可能重新从主存中获取变量副本(read-load-use),也有可能直接引用原来的副本(use),也就是说 read,load,use顺序可以由JVM实现系统决
定。
线程不能直接为主存中中字段赋值,它会将值指定给工作内存中的变量副本(assign),完成后这个变量副本会同步到主存储区(store-write),至于何时同步过去,根据JVM实现系统决定。
有该字段,则会从主内存中将该字段赋值到工作内存中,这个过程为read-load,完成后线程会引用该变量副本。