国产精品无码一区二区三区太,亚洲一线产区二线产区区别,欧美A区,人妻jealousvue人妻

×

手寫JAVA虛擬機(jī)(二)——實(shí)現(xiàn)java命令行

  • 作者:新網(wǎng)
  • 來(lái)源:新網(wǎng)
  • 瀏覽:100
  • 2018-04-26 15:48:45

咱們都知道,咱們編譯.java并運(yùn)轉(zhuǎn).class文件時(shí),需求一些java指令,如最簡(jiǎn)略的helloworld程序。java初學(xué)者可以看一下下面的教程。

   t0168e141ebeb2a01ea.jpg

<div>  咱們都知道,咱們編譯.java并運(yùn)轉(zhuǎn).class文件時(shí),需求一些java指令,如最簡(jiǎn)略的helloworld程序。java初學(xué)者可以看一下下面的教程。
  這兒的程序最好不要加包名,因?yàn)榧恿税脑捑幾g和運(yùn)轉(zhuǎn)需求有所改動(dòng)。
  看這兒的指令。javac為編譯指令,咱們知道java的特點(diǎn)是一次編譯,處處運(yùn)轉(zhuǎn)。這兒的編譯指的就是javac,關(guān)于java程序即.java文件,先要用javac編譯成字節(jié)碼。然后將字節(jié)碼(.class文件)放到j(luò)ava虛擬機(jī)中運(yùn)轉(zhuǎn),即上圖中的java HelloWorld,java虛擬機(jī)把字節(jié)碼翻譯成對(duì)應(yīng)機(jī)器上的機(jī)器指令,再由機(jī)器來(lái)履行詳細(xì)的機(jī)器指令。也就是說(shuō)java程序員是直接與java虛擬機(jī)交互,簡(jiǎn)介與機(jī)器交互。所以虛擬機(jī)完結(jié)的是java指令,也就是咱們要完結(jié)的是java這個(gè)指令的功用。
  那么咱們把榜首個(gè)方針定為,完結(jié)簡(jiǎn)略的指令行。即咱們經(jīng)過(guò)指令行能夠輸入一些內(nèi)容,虛擬機(jī)讀取之后能夠給必定的反應(yīng)。
  GO言語(yǔ)中有兩個(gè)和指令行相關(guān)的包,分別是os和flag(java中以類庫(kù)即jar文件導(dǎo)入,go中直接以包的辦法導(dǎo)入)。
  首先在GOPATH目錄下的src里邊新建一個(gè)jvmgo文件夾作為咱們的作業(yè)空間目錄,jvmgo里邊再新建一個(gè)ch01為咱們的榜首個(gè)方針源碼文件夾,增加cmd.go文件。
  在cmd.go里邊輸入如下代碼(因?yàn)椴┛蛨@的增加代碼辦法不支持go言語(yǔ)上色,所以選用C言語(yǔ)上色,高亮可能不太正確)
  package main import "flag" import "fmt" import "os" //界說(shuō)Cmd結(jié)構(gòu)體 type Cmd struct{ helpFlag bool versionFlag bool cpOption string class string args []string } //解析指令行參數(shù) func parseCmd() *Cmd { cmd:=&Cmd{} //將printUsage函數(shù)傳給flag.Usage flag.Usage=printUsage //設(shè)置各種解析的選項(xiàng) 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") //一切選項(xiàng)設(shè)置完結(jié)后調(diào)用flag.Parse解析一切選項(xiàng),假如Parse失利,則調(diào)用flag.Usage打印協(xié)助信息 flag.Parse() //調(diào)用flag.Args函數(shù)捕獲未被解析的參數(shù),榜首個(gè)參數(shù)為主類名,后邊的為傳遞給主類的參數(shù) 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包,接著引入了三個(gè)包os,flag,fmt。os和flag都是處理指令行所需的包,fmt類似于C言語(yǔ)的printf和scanf等格式化IO。再往下界說(shuō)了一個(gè)結(jié)構(gòu)體Cmd,用來(lái)這個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)格式化存儲(chǔ)輸入的指令行信息。helpFlag參數(shù)為指令行是否懇求help,versionFlag參數(shù)為指令行是否懇求version,cpOption為指令行傳入的classpath即方針.class文件地點(diǎn)文件夾,class為指令行傳入的.class文件名(不包括.class),args為指令行傳入的其他參數(shù)。
  緊接著是一個(gè)parseCmd函數(shù)(go言語(yǔ)有函數(shù)和辦法之分,辦法調(diào)用需求receiver,函數(shù)調(diào)用則不需求 ),回來(lái)值為*Cmd,用來(lái)解析cmd傳過(guò)來(lái)的參數(shù)。該函數(shù)里邊先聲明一個(gè)cmd并給這個(gè)cmd賦值一個(gè)新建的Cmd對(duì)象。go言語(yǔ)中的“:=”為聲明并賦值,而"="為賦值。先把printUsage的函數(shù)賦值給flag.Usage,然后調(diào)用flag設(shè)置需求解析的選項(xiàng),悉數(shù)解析結(jié)束,調(diào)用Parse函數(shù)解析一切選項(xiàng)。解析成功則結(jié)束,解析失利則調(diào)用printUsage打印到控制臺(tái)。
  flag.Args能夠捕獲其他沒(méi)有被解析的參數(shù)。上面解析成功之后,榜首個(gè)參數(shù)就是主類名,剩余的就是傳給主類的參數(shù)。
  東西類編寫完結(jié),下一個(gè)是
  主函數(shù)。先上主函數(shù)代碼:
  package main import "fmt" func main() { //調(diào)用parseCmd解析指令行參數(shù) cmd:=parseCmd() if cmd.versionFlag{ //輸入了-version選項(xiàng) fmt.Println("version 0.0.1") }else if cmd.helpFlag||cmd.class==""{ //輸入了-help選項(xiàng) printUsage() }else{ //發(fā)動(dòng)jvm stratJVM(cmd) } } func stratJVM(cmd *Cmd){ fmt.Printf("classpath:%s class:%s args:%v ", cmd.cpOption,cmd.class,cmd.args) }
  跟java類似,在go里邊main是一個(gè)特殊的包,go程序的入口就是main函數(shù),可是不接受任何參數(shù),也不能有回來(lái)值。main函數(shù)先調(diào)用parseCmd解析指令行參數(shù),假如是-version則回來(lái)版本號(hào),假如是-help則回來(lái)協(xié)助信息,假如是其他則發(fā)動(dòng)jvm,這兒用一些輸出信息“偽裝”發(fā)動(dòng)了jvm,真正的jvm代碼后邊會(huì)加上。
  至此,對(duì)指令行的解析作業(yè)悉數(shù)完結(jié)。先展現(xiàn)一下整個(gè)作業(yè)目錄的結(jié)構(gòu),不然后邊編譯運(yùn)轉(zhuǎn)的時(shí)分會(huì)犯錯(cuò)。
  咱們的作業(yè)目錄是D盤下的JVM里的goWorkSpace,再下面src,jvmgo,ch01,ch01里邊包括的是咱們的go文件。
  來(lái)測(cè)驗(yàn)一下,翻開(kāi)一指令行,輸入go install jvmgoch01。這個(gè)指令是運(yùn)用go.exe來(lái)install文件,這個(gè)文件存在于GOPATH下面的文件夾(jvmgoch01中),結(jié)果如圖:
  然后在作業(yè)空間(GOPATH)的bin文件夾中就多出了一個(gè)ch01.exe。
  在此處翻開(kāi)指令行。能夠進(jìn)行一些操作:
  到這兒,咱們的指令行東西就完結(jié)了,盡管還沒(méi)有觸及真正的虛擬機(jī)規(guī)劃,但這也是虛擬機(jī)運(yùn)轉(zhuǎn)的重要一步,后邊會(huì)逐漸介紹虛擬機(jī)的規(guī)劃。
  同理,如果在unlock操作中,就是釋放了鎖,然后unpark,這兒就不詳細(xì)講了。
  咱們知道HashMap不是一個(gè)線程安全的容器,最簡(jiǎn)略的辦法使HashMap變成線程安全就是運(yùn)用Collections.synchronizedMap,它是對(duì)HashMap的一個(gè)包裝
  public static Map m=Collections.synchronizedMap(new HashMap());
  同理關(guān)于List,Set也供給了類似辦法。
  可是這種辦法只適合于并發(fā)量比較小的狀況。
  咱們來(lái)看下synchronizedMap的完成
  它會(huì)將HashMap包裝在里面,然后將HashMap的每個(gè)操作都加上synchronized。
  由于每個(gè)辦法都是獲取同一把鎖(mutex),這就意味著,put和remove等操作是互斥的,大大減少了并發(fā)量。
  下面來(lái)看下ConcurrentHashMap是怎么完成的
  在 ConcurrentHashMap內(nèi)部有一個(gè)Segment段,它將大的HashMap切分成若干個(gè)段(小的HashMap),然后讓數(shù)據(jù)在每一段上Hash,這樣多個(gè)線程在不同段上的Hash操作一定是線程安全的,所以只需要同步同一個(gè)段上的線程就可以了,這樣完成了鎖的別離,大大增加了并發(fā)量。
  在運(yùn)用ConcurrentHashMap.size時(shí)會(huì)比較費(fèi)事,由于它要計(jì)算每個(gè)段的數(shù)據(jù)和,在這個(gè)時(shí)分,要把每一個(gè)段都加上鎖,然后再做數(shù)據(jù)計(jì)算。這個(gè)就是把鎖別離后的小小壞處,可是size辦法應(yīng)該是不會(huì)被高頻率調(diào)用的辦法。
  在完成上,不運(yùn)用synchronized和lock.lock而是盡量運(yùn)用trylock,一起在HashMap的完成上,也做了一點(diǎn)優(yōu)化。這兒就不提了。
 

免責(zé)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn)自行上傳,本網(wǎng)站不擁有所有權(quán),也不承認(rèn)相關(guān)法律責(zé)任。如果您發(fā)現(xiàn)本社區(qū)中有涉嫌抄襲的內(nèi)容,請(qǐng)發(fā)送郵件至:operations@xinnet.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),本站將立刻刪除涉嫌侵權(quán)內(nèi)容。

免費(fèi)咨詢獲取折扣

Loading