时间:2021-07-16 | 标签: | 作者:Q8 | 来源:网络
小提示:您能找到这篇{手写JAVA虚拟机(二)——实现java命令行}绝对不是偶然,我们能帮您找到潜在客户,解决您的困扰。如果您对本页介绍的手写JAVA虚拟机(二)——实现java命令行内容感兴趣,有相关需求意向欢迎拨打我们的服务热线,或留言咨询,我们将第一时间联系您! |
咱们都知道,咱们编译.java并运转.class文件时,需求一些java指令,如最简略的helloworld程序。java初学者可以看一下下面的教程。
这儿的程序最好不要加包名,因为加了包名的话编译和运转需求有所改动。
看这儿的指令。javac为编译指令,咱们知道java的特点是一次编译,处处运转。这儿的编译指的就是javac,关于java程序即.java文件,先要用javac编译成字节码。然后将字节码(.class文件)放到java虚拟机中运转,即上图中的java HelloWorld,java虚拟机把字节码翻译成对应机器上的机器指令,再由机器来履行详细的机器指令。也就是说java程序员是直接与java虚拟机交互,简介与机器交互。所以虚拟机完结的是java指令,也就是咱们要完结的是java这个指令的功用。
那么咱们把榜首个方针定为,完结简略的指令行。即咱们经过指令行能够输入一些内容,虚拟机读取之后能够给必定的反应。
GO言语中有两个和指令行相关的包,分别是os和flag(java中以类库即jar文件导入,go中直接以包的办法导入)。
首先在GOPATH目录下的src里边新建一危机公关趋势个jvmgo文件夹作为咱们的作业空间目录,jvmgo里边再新建一个ch01为咱们的榜首个方针源码文件夹,增加cmd.go文件。
在cmd.go里边输入如下代码(因为博客园的增加代码办法不支持go言语上色,所以选用C言语上色,高亮可能不太正确)
package main import "flag" import "fmt" import "os" //界说Cmd结构体 type Cmd struct{ helpFlag bool versionFlag bool cpOption string class string args []string } //解析指令行参数 func parseCmd() *Cmd { cmd:=&Cmd{} //将printUsage函数传给flag.Usage flag.Usage=printUsage //设置各种解析的选项 flag.BoolVar(&cmd.helpFlag, "help", false, "print help message") flag.BoolVar(&cmd.helpFlag, "?", false, "print help message") flag.BoolVar(&cmd.versionFlag, "version", false, "print version and exit") flag.StringVar(&cmd.cpOption, "classpath", "", "classpath") flag.StringVar(&cmd.cpOption, "cp", "", "classpath") //一切选项设置完结后调用flag.Parse解析一切选项,假如Parse失利,则调用flag.Usage打印协助信息 flag.Parse() //调用flag.Args函数捕获未被解析的参数,榜首个参数为主类名,后边的为传递给主类的参数 args:=flag.Args() if len(args)>0{ cmd.class=args[0] cmd.args=args[1:] } return cmd } func printUsage() {电商运营改造方案 fmt.Printf("Usage:%s[-options] class [args...] ",os.Args[0]) }
榜首行为包名,main包,接着引入了三个包os,flag,fmt。os和flag都是处理指令行所需的包,fmt类似于C言语的printf和scanf等格式化IO。再往下界说了一个结构体Cmd,用来这个数据结构来格式化存储输入的指令行信息。helpFlag参数为指令行是否恳求help,versionFlag参数为指令行是否恳求version,cpOption为指令行传入的classpath即方针.class文件地点文件夹,class为指令行传入的.class文件名(不包括.class),args为指令行传入的其他参数。
紧接着是一个parseCmd函数(go言语有函数和办法之分,办法调用需求receiver,函数调用则不需求 ),回来值为*Cmd,用来解析cmd传过来的参数。该函数里边先声明一个cmd并给这个cmd赋值一个新建的Cmd对象。go言语中的“:=”为声明并赋值,而"="为赋值。先把printUsage的函数赋值给flag.Usage,然后调用flag设置需求解析的选项,悉数解析结束,调用Parse函数解析一切选项。解析成功则结束,解析失利则调用printUsage打印到控制台。
flag.Args能够捕获其他没有被解析的参数。上面解析成功之后,榜首个参数就是主类名,剩余的就是传给主类的参数。
东西类编写完结,下一个是
主函数。先上主函数代码:
package main import "fmt" func main() { //调用parseCmd解析指令行参数 cmd:=parseCmd() if cmd.versionFlag{ //输入了-version选项 fmt.Println("version 0.0.1") }else if cmd.helpFlag||cmd.class==""{ //输入了-help选项 printUsage() }else{ //发动jvm stratJVM(cmd) } } func stratJVM(cmd *Cmd){ fmt.Printf("classpath:%s class:%s args:%v ", cmd.cpOption,cmd.class,cmd.args) }
跟java类似,在go里边main是一个特殊的包,go程序的入口就是main函数,可是不接受任何参数,也不能有回来值。main函数先调用parseCmd解析指令行参数,假如是-version则回来版本号,假如是-help则回来协助信息,假如是其他则发动jvm,这儿用一些输出信息“伪装”发动了jvm,真正的jvm代码后边会加上。
至此,对指令行的解析作业悉数完结。先展现一下整个作业目录的结构,不然后边编译运转的时分会犯错。
咱们的作业目录是D盘下的JVM里的goWorkSpace,再下面src,jvmgo,ch01,ch01里边包括的是咱们的go文件。
来测验一下,翻开一指令行,输入go install jvmgoch01。这个指令是运用go.exe来install文件,这个文件存在于GOPATH下面的文件夹(jvmgoch01中),结果如图:
然后在作业空间(GOPATH)的bin文件夹中就多出了一个ch01.exe。
在此处翻开指令行。能够进行一些操作:
到这儿,咱们的指令行东西就完结了,尽管还没有触及真正的虚拟机规划,但这也是虚拟机运转的重要一步,后边会逐渐介绍虚拟机的规划。
同理,如果在unlock操作中,就是释放了锁,然后unpark,这儿就不详细讲了。
咱们知道HashMap不是一个线程安全的容器,最简略的办法使HashMap变成线程安全就是运用Collections.synchronizedMap,它是对HashMap的一个包装
public static Map m=Collections.synchronizedMap(new HashMap());
同理关于List,Set也供给了类似办法。
可是这种办法只适合于并发量比较小的状况。
咱们来看下synchronizedMap的完成
它会将HashMap包装在里面,然后将HashMap的每个操作都加上synchronized。
由于每个办法都是获取同一把锁(mutex),这就意味着,put和remove等操作是互斥的,大大减少了并发量。
下面来看下ConcurrentHashMap是怎么完成的
在 ConcurrentHashMap内部有一个Segment段,它将大的HashMap切分成若干个段(小的HashMap),然后让数据在每一段上Hash,这样多个线程在不同段上的Hash操作一定是线程安全的,所以只需要同步同一个段上的线程就可以了,这样完成了锁的别离,大大增加了并发量。
在运用ConcurrentHashMap.size时会比较费事,由于它要计算每个段的数据和,在这个时分,要把每一个段都加上锁,然后再做数据计算。这个就是把锁别离后的小小坏处,可是size办法应该是不会被高频率调用的办法。
在完成上,不运用synchronized和lock.lock而是尽量运用trylock,一起在HashMap的完成上,也做了一点优化。这儿就不提了。
|
上一篇:Linux 容器 vs 虚拟机 —— 谁更胜一筹?
下一篇:深入理解Java虚拟机(二)
小提示:您应该对本页介绍的“手写JAVA虚拟机(二)——实现java命令行”相关内容感兴趣,若您有相关需求欢迎拨打我们的服务热线或留言咨询,我们尽快与您联系沟通手写JAVA虚拟机(二)——实现java命令行的相关事宜。
关键词:手写JAVA虚拟机(二)——实