码迷,mamicode.com
首页 > 编程语言 > 详细

Java多线程学习笔记(一)

时间:2016-05-03 18:22:57      阅读:144      评论:0      收藏:0      [点我收藏+]

标签:

首先推荐一些好文:

http://blog.csdn.net/Johnnyz1234/article/details/41679665  

http://www.cnblogs.com/nexiyi/p/java_memory_model_and_thread.html  

http://www.cnblogs.com/dingyingsi/p/3760447.html


研究多线程是为了解决线程间的资源同步问题和线程间共同协作解决问题。


计算机内存模型:

技术分享

基于高速缓存的存储交互很好的解决了处理器与内存之间的矛盾(内存的读写速度跟不上CPU的读写速度),也引入了新的问题:缓存一致性问题。在多处理器系统中,每个处理器有自己的高速缓存,而他们又共享同一块内存(main memory 主内存),当多个处理器运算都涉及到同一块内存区域的时候,就有可能发生缓存不一致的现象。为了解决这一问题,需要各个处理器运行时都遵循一些协议(MSI、MESI、MOSI及Dragon Protocol等),在运行时需要将这些协议保证数据的一致性。


技术分享

为了使得处理器内部的运算单元能竟可能被充分利用,处理器可能会对输入代码进行乱起执行(Out-Of-Order Execution)优化,处理器会在计算之后将对乱序执行的代码进行结果重组,保证结果准确性。

Java内存模型:

Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样底层细节。此处的变量与Java编程时所说的变量不一样,指包括了实例字段、静态字段和构成数组对象的元素,但是不包括局部变量与方法参数,后者是线程私有的,不会被共享。

Java内存模型中规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存(可以与前面将的处理器的高速缓存类比),线程的工作内存中保存了该线程使用到的变量到主内存副本拷贝,线程对变量的所有操作(读取、赋值)都必须在工作内存中进行,而不能直接读写主内存中的变量。不同线程之间无法直接访问对方工作内存中的变量,线程间变量值的传递均需要在主内存来完成,线程、主内存和工作内存的交互关系和计算机的内存模型很类似。Java虚拟机内存模型中定义的内存访问操作与硬件的缓存访问操作是具有可比性的。


技术分享




JVM的逻辑内存模型:

技术分享

线程私有

程序计数器、Java栈、本地方法栈是线程私有的,声明周期跟创建它的线程一样。

由于Java 虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储。

Java 方法执行的内存模型:

虚拟机栈(Java栈)描述的是Java 方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame )用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型,它不等同于对象本身,根据不同的虚拟机实现,它可能是一个指向对象起始地址的引用指针,也可能指向一个代表对象的句柄或者其他与此对象相关的位置)和returnAddress 类型(指向了一条字节码指令的地址)。


虚拟机栈为虚拟机执行Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native 方法服务。


线程共享

Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存


方法区(Method Area)与Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java 堆区分开来。


因此可以进一步理解为:栈其实就相当于线程的工作内存,相当于一个任务,而堆相当于主内存。(有待进一步理解和验证)


多个线程访问的时候,属于线程共享的内存需要考虑同步问题。

1:虚拟机堆-存在堆中类的实例

2:方法区-类的方法作用域中的类变量

多个线程有可能会同时访问这两类数据的时候,我们需要给它们加上锁,先到先得的每次只准单一访问。Java中的对象的锁是排他锁,每个类和对象都会有对应的锁。常用触发锁的方式是通过互斥量的方式来同步共享资源,使得对代码块的访问每次都只允许一个对象访问。在Java语法中,我们至少有两种方式来同步代码块来对共享资源进行同步,如:synchronized 和ReentrantLock上锁的方式。


这些理论基础只是为了更好的理解线程的工作原理。





Java多线程学习笔记(一)

标签:

原文地址:http://blog.csdn.net/wuqinghai2012/article/details/51301915

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!