<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>理解 on 庞玉栋个人博客</title><link>https://pangyd.com/tags/%E7%90%86%E8%A7%A3/</link><description>Recent content in 理解 on 庞玉栋个人博客</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Fri, 24 Nov 2017 22:55:12 +0800</lastBuildDate><atom:link href="https://pangyd.com/tags/%E7%90%86%E8%A7%A3/index.xml" rel="self" type="application/rss+xml"/><item><title>深入理解Java虚拟机到底是什么</title><link>https://pangyd.com/post/180-java/</link><pubDate>Fri, 24 Nov 2017 22:54:49 +0800</pubDate><guid>https://pangyd.com/post/180-java/</guid><description>&lt;p>什么是Java虚拟机&lt;/p>&lt;div class="content rich" data-reactid=".0.1.0.0.0.1.1.1">&lt;p>作为一个Java程序员，我们每天都在写Java代码，我们写的代码都是在一个叫做Java虚拟机的东西上执行的。但是如果要问什么是虚拟机，恐怕很多人就会模棱两可了。在本文中，我会写下我对虚拟机的理解。因为能力所限，可能有些地方描述的不够欠当。如果你有不同的理解，欢迎交流。&lt;/p>&lt;p>我们都知道java程序必须在虚拟机上运行。那么虚拟机到底是什么呢？先看网上搜索到的比较靠谱的解释：&lt;/p>&lt;p>虚拟机是一种抽象化的计算机，通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机有自己完善的硬体架构，如处理器、堆栈、寄存器等，还具有相应的指令系统。JVM屏蔽了与具体操作系统平台相关的信息，使得Java程序只需生成在Java虚拟机上运行的目标代码（字节码），就可以在多种平台上不加修改地运行。&lt;/p>&lt;p>这种解释应该算是正确的，但是只描述了虚拟机的外部行为和功能，并没有针对内部原理做出说明。一般情况下我们不需要知道虚拟机的运行原理，只要专注写java代码就可以了，这也正是虚拟机之所以存在的原因--屏蔽底层操作系统平台的不同并且减少基于原生语言开发的复杂性，使java这门语言能够跨各种平台（只要虚拟机厂商在特定平台上实现了虚拟机），并且简单易用。这些都是虚拟机的外部特性，但是从这些信息来解释虚拟机，未免太笼统了，无法让我们知道内部原理。&lt;/p>&lt;p>从进程的角度解释JVM&lt;/p>&lt;p>让我们尝试从操作系统的层面来理解虚拟机。我们知道，虚拟机是运行在操作系统之中的，那么什么东西才能在操作系统中运行呢？当然是进程，因为进程是操作系统中的执行单位。可以这样理解，当它在运行的时候，它就是一个操作系统中的进程实例，当它没有在运行时（作为可执行文件存放于文件系统中），可以把它叫做程序。&lt;/p>&lt;p>对命令行比较熟悉的同学，都知道其实一个命令对应一个可执行的二进制文件，当敲下这个命令并且回车后，就会创建一个进程，加载对应的可执行文件到进程的地址空间中，并且执行其中的指令。下面对比C语言和Java语言的HelloWorld程序来说明问题。&lt;/p>&lt;p>首先编写C语言版的HelloWorld程序。&lt;/p>&lt;p>&lt;span>[cpp]&lt;/span>view plain copy&lt;/p>&lt;p>#include&lt;/p>&lt;p>#include&lt;/p>&lt;p>int main(void) {&lt;/p>&lt;p>printf("hello world\n");&lt;/p>&lt;p>return 0;&lt;/p>&lt;p>}&lt;/p>&lt;p>编译C语言版的HelloWorld程序：&lt;/p>&lt;p>&lt;span>[plain]&lt;/span>view plain copy&lt;/p>&lt;p>gcc HelloWorld.c -o HelloWorld&lt;/p>&lt;p>运行C语言版的HelloWorld程序：&lt;/p>&lt;p>&lt;span>[plain]&lt;/span>view plain copy&lt;/p>&lt;p>zhangjg@linux:/deve/workspace/HelloWorld/src$ ./HelloWorld&lt;/p>&lt;p>hello world&lt;/p>&lt;p>gcc编译器编译后的文件直接就是可被操作系统识别的二进制可执行文件，当我们在命令行中敲下 ./HelloWorld这条命令的时候， 直接创建一个进程， 并且将可执行文件加载到进程的地址空间中， 执行文件中的指令。&lt;/p>&lt;p>作为对比， 我们看一下Java版HelloWord程序的编译和执行形式。&lt;/p>&lt;p>首先编写源文件HelloWord.java ：&lt;/p>&lt;p>&lt;span>[java]&lt;/span>view plain copy&lt;/p>&lt;p>public class HelloWorld {&lt;/p>&lt;p>public static void main(String[] args) {&lt;/p>&lt;p>}&lt;/p>&lt;p>}&lt;/p>&lt;p>编译Java版的HelloWorld程序：&lt;/p>&lt;p>&lt;span>[java]&lt;/span>view plain copy&lt;/p>&lt;p>zhangjg@linux:/deve/workspace/HelloJava/src$ javac HelloWorld.java&lt;/p>&lt;p>zhangjg@linux:/deve/workspace/HelloJava/src$ ls&lt;/p>&lt;p>HelloWorld.class HelloWorld.java&lt;/p></description></item><item><title>转载自【 Java编程精选】深入理解 Java final 变量的内存模型</title><link>https://pangyd.com/post/52-java-java-final/</link><pubDate>Fri, 11 Aug 2017 22:11:15 +0800</pubDate><guid>https://pangyd.com/post/52-java-java-final/</guid><description>&lt;p>对于 final 域，编译器和处理器要遵守两个重排序规则：&lt;/p>&lt;ul class="list-paddingleft-2">&lt;li>&lt;p>在构造函数内对一个 final 域的写，与随后把这个构造对象的引用赋值给一个变量，这两个操作之间不能重排序&lt;/p>&lt;/li>&lt;li>&lt;p>初次读一个包含 final 域的对象的引用，与随后初次读这个 final 域，这两个操作之间不能重排序&lt;/p>&lt;/li>&lt;/ul>&lt;p>举个例子：&lt;/p>&lt;table cellpadding="0" cellspacing="0" width="620" height="NaN" class="layui-table">&lt;tbody>&lt;tr>&lt;td class="" width="NaN" height="NaN">&lt;div class="" style="text-align: right">1&lt;/div>&lt;div class="" style="text-align: right">2&lt;/div>&lt;div class="" style="text-align: right">3&lt;/div>&lt;div class="" style="text-align: right">4&lt;/div>&lt;div class="" style="text-align: right">5&lt;/div>&lt;div class="" style="text-align: right">6&lt;/div>&lt;div class="" style="text-align: right">7&lt;/div>&lt;div class="" style="text-align: right">8&lt;/div>&lt;div class="" style="text-align: right">9&lt;/div>&lt;div class="" style="text-align: right">10&lt;/div>&lt;div class="" style="text-align: right">11&lt;/div>&lt;div class="" style="text-align: right">12&lt;/div>&lt;div class="" style="text-align: right">13&lt;/div>&lt;div class="" style="text-align: right">14&lt;/div>&lt;div class="" style="text-align: right">15&lt;/div>&lt;div class="" style="text-align: right">16&lt;/div>&lt;div class="" style="text-align: right">17&lt;/div>&lt;div class="" style="text-align: right">18&lt;/div>&lt;div class="" style="text-align: right">19&lt;/div>&lt;div class="" style="text-align: right">20&lt;/div>&lt;/td>&lt;td class="" width="585" height="NaN">&lt;div class="">&lt;code class="">public&lt;/code> &lt;code class="">class&lt;/code> &lt;code class="">FinalExample {&lt;/code>&lt;/div>&lt;div class="">&lt;code class="">&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code>&lt;code class="">int&lt;/code> &lt;code class="">i;&lt;/code>&lt;code class="">// 普通变量&lt;/code>&lt;/div>&lt;div class="">&lt;code class="">&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code>&lt;code class="">final&lt;/code> &lt;code class="">int&lt;/code> &lt;code class="">j;&lt;/code>&lt;code class="">// final 变量&lt;/code>&lt;/div>&lt;div class="">&lt;code class="">&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code>&lt;code class="">static&lt;/code> &lt;code class="">FinalExample obj;&lt;/code>&lt;/div>&lt;div class="">&amp;nbsp;&lt;/div>&lt;div class="">&lt;code class="">&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code>&lt;code class="">public&lt;/code> &lt;code class="">FinalExample() {&lt;/code>&lt;/div>&lt;div class="">&lt;code class="">&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code>&lt;code class="">i = &lt;/code>&lt;code class="">1&lt;/code>&lt;code class="">;&lt;/code>&lt;code class="">// 写普通域&lt;/code>&lt;/div>&lt;div class="">&lt;code class="">&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code>&lt;code class="">j = &lt;/code>&lt;code class="">2&lt;/code>&lt;code class="">;&lt;/code>&lt;code class="">// 写 final 域&lt;/code>&lt;/div>&lt;div class="">&lt;code class="">&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code>&lt;code class="">}&lt;/code>&lt;/div>&lt;div class="">&amp;nbsp;&lt;/div>&lt;div class="">&lt;code class="">&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code>&lt;code class="">public&lt;/code> &lt;code class="">static&lt;/code> &lt;code class="">void&lt;/code> &lt;code class="">writer() {&lt;/code>&lt;code class="">// 写线程 A 执行&lt;/code>&lt;/div>&lt;div class="">&lt;code class="">&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code>&lt;code class="">obj = &lt;/code>&lt;code class="">new&lt;/code> &lt;code class="">FinalExample();&lt;/code>&lt;/div>&lt;div class="">&lt;code class="">&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code>&lt;code class="">}&lt;/code>&lt;/div>&lt;div class="">&amp;nbsp;&lt;/div>&lt;div class="">&lt;code class="">&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code>&lt;code class="">public&lt;/code> &lt;code class="">static&lt;/code> &lt;code class="">void&lt;/code> &lt;code class="">reader() {&lt;/code>&lt;code class="">// 读线程 B 执行&lt;/code>&lt;/div>&lt;div class="">&lt;code class="">&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code>&lt;code class="">FinalExample object = obj;&lt;/code>&lt;/div>&lt;div class="">&lt;code class="">&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code>&lt;code class="">int&lt;/code> &lt;code class="">a = object.i;&lt;/code>&lt;/div>&lt;div class="">&lt;code class="">&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code>&lt;code class="">int&lt;/code> &lt;code class="">b = object.j;&lt;/code>&lt;/div>&lt;div class="">&lt;code class="">&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code>&lt;code class="">}&lt;/code>&lt;/div>&lt;div class="">&lt;code class="">}&lt;/code>&lt;/div>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>&lt;p>这里假设一个线程 A 执行 writer ()方法,随后另一个线程 B 执行 reader ()方法。&lt;/p></description></item></channel></rss>