Java 和 Go 在并發(fā)實(shí)現(xiàn)中的區(qū)別

我一直想討論 Golang 和 Java,許多朋友都希望討論下。而我碰巧有相當(dāng)長(zhǎng)的 ?Java 編程語言經(jīng)驗(yàn),并且在過去的幾年中,我接觸并使用了 Golang。
Java 是一門高級(jí)編程語言,在實(shí)現(xiàn)其語言時(shí)采用了對(duì)象方法。Java 是一種非常成熟和穩(wěn)定的編程語言,在世界上使用最廣泛。特別是對(duì)于企業(yè)級(jí)別平均超過 80% 的應(yīng)用程序,使用的都是 Java。Java 本身是在 1990 年左右由 SUN Microsystems 開發(fā)的。
Golang 是由 Google 創(chuàng)建的一種編程語言,在 2009 年左右開源,Golang 最初使用 C 實(shí)現(xiàn)的。與 Java 一樣擁有垃圾收集,不同之處在于 Golang 代碼將被編譯為計(jì)算機(jī)本地代碼,因此與基于虛擬機(jī)的編程語言相比,它會(huì)有更好的性能。
Golang 幾乎像 Java 等 OOP 一樣,但是它不是完全的 OOP,或者現(xiàn)在還不能被稱為完全的 OOP 編程語言。由于其缺乏對(duì) OOP 的支持,有些特性會(huì)比較麻煩。但面向?qū)ο笥兴约旱膯栴}。Go 強(qiáng)調(diào)使用組合來復(fù)用,而不是繼承。
并發(fā)是一種用于解決多個(gè)請(qǐng)求或多個(gè)進(jìn)程同時(shí)完成的問題的編程技術(shù),并發(fā)進(jìn)程的主要特征是不能在某個(gè)資源上同時(shí)執(zhí)行一個(gè)進(jìn)程和另一個(gè)進(jìn)程。通常一個(gè)進(jìn)程與另一個(gè)進(jìn)程交替進(jìn)行。因?yàn)樗浅??,所以有時(shí)看起來好像是一起完成的。
如果我們嘗試進(jìn)行分析,那么這個(gè)并發(fā)過程就像處理許多請(qǐng)求的飯店工作人員。他將堆積所有即將到來的請(qǐng)求,并一一完成。這樣,如果所有進(jìn)程都由他們自己執(zhí)行,則該進(jìn)程將花費(fèi)很長(zhǎng)時(shí)間,因?yàn)闀?huì)發(fā)生隊(duì)列并且這些工作人員都已耗盡。為了處理這些許多請(qǐng)求,解決方案是增加額外的工作人員,以便可以同時(shí)執(zhí)行工作流程,并更快地為訪問者的請(qǐng)求提供服務(wù)。
它與并行性的概念不同,并行性有時(shí)會(huì)與并發(fā)性概念混淆。并行處理是解決大問題的一種方法,通常這樣做會(huì)花費(fèi)很長(zhǎng)時(shí)間。通過將解決方案分成更小的部分來完成解決方案。這些小任務(wù)是獨(dú)立的,互不影響,并且同時(shí)完成。
在并行編程技術(shù)中,必須存在并發(fā),但是并發(fā)并不一定意味著存在并行進(jìn)程。

Java 使用 OS 線程通過 Java 運(yùn)行時(shí)管理的線程來完成并行進(jìn)程。Golang 通過 Goroutine 使用線程 os 完成并行進(jìn)程。在 Java 和 Golang 之間的并行概念中,沒有太大區(qū)別,幾乎相同,只是名稱不同。
并發(fā)概念不同。在 Java 中,這是通過將 Java 運(yùn)行時(shí)線程映射到 os線 程來完成的。同時(shí),golang 使用此 goroutine 映射到 golang 上的調(diào)度程序,將其映射到更深層次。
Goroutine 本身不是線程系統(tǒng)或由 os 線程管理的線程。但是,這種想法更多的是將函數(shù)協(xié)程處理到 os 線程中的多路復(fù)用器。這樣,當(dāng)發(fā)生進(jìn)程阻塞時(shí),它將被移至未使用的線程或綠色線程,Go 調(diào)度程序的任務(wù)是將此綠色線程映射到 OS 線程,并將 goroutine 分配到空閑的綠色線程中。
乍一看,goroutine 概念與 Reactive .io 中以 Reactore 3 或 RxJava 表示的 React Java 的非阻塞概念幾乎相同。但是,Java反 應(yīng)流概念比 goroutines 具有更高級(jí)的方法。
Java 并發(fā)模型和 Golang
盡管在并發(fā)問題中有不同的實(shí)現(xiàn)方法,但是模型幾乎相同。
異步過程
Java
創(chuàng)建從 Thread 類擴(kuò)展的類。 實(shí)現(xiàn) Runnable 的接口。
Golang
Goroutine 開始
同步過程
Java
方法上的同步塊。 使用 java.util.concurrent 包中的 Lock.ReentrantLock
Golang
使用通道的概念,即術(shù)語“不通過共享內(nèi)存進(jìn)行通信和通過通信共享內(nèi)存”的行話的實(shí)現(xiàn)。 Sync.Mutex 鎖定資源。
進(jìn)程間通訊
Java
使用 object.wait(),object.Notify() 或 object.NotifyAll() 方法。 在多個(gè)線程上共享塊隊(duì)列 使用 PipeReader 和 PipeWriter 方法
Golang
使用 channel 使用 WaitGroup
樣例代碼
SampleTask.java
package?com.dhfr.concurrency;
import?java.util.concurrent.TimeUnit;
public?class?SampleTask?implements?Runnable?{
????private?String?name;
????public?SampleTask(String?name)?{
????????this.name?=?name;
????}
????public?String?getName()?{
????????return?name;
????}
????public?void?run()?{
????????Long?timeDuration?=?(long)Math.random()?*?11;
????????System.out.println("Pengerjaan?Task?"+?name);
????????try?{
????????????TimeUnit.SECONDS.sleep(timeDuration);
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????}
}
ApplicationMain.java
package?com.dhfr.concurrency;
import?java.util.concurrent.Executors;
import?java.util.concurrent.ThreadPoolExecutor;
public?class?ApplicationMain?{
????public?static?void?main(String[]?args)?{
????????ThreadPoolExecutor?threadPoolExecutor=?(ThreadPoolExecutor)?Executors.newFixedThreadPool(6);
????????for?(int?i=0;i<10;i++)?{
????????????SampleTask?sampleTask=new?SampleTask("Task?ke?"+i)?;
????????????System.out.println("Sebuah?task?sudah?di?tambahkan?dengan?nama?"+sampleTask.getName());
????????????threadPoolExecutor.execute(sampleTask);
????????}
????????System.out.println("Maksimun?thread?yang?terjadi?adalah?"+threadPoolExecutor.getMaximumPoolSize());
????????threadPoolExecutor.shutdown();
????}
}
view?raw
如果我們執(zhí)行上面的代碼,產(chǎn)生如下輸出:
SSebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?0
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?1
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?2
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?3
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?4
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?5
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?6
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?7
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?8
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?9
Maksimun?thread?yang?terjadi?adalah?6
Pengerjaan?Task?Task?ke?0
Pengerjaan?Task?Task?ke?1
Pengerjaan?Task?Task?ke?3
Pengerjaan?Task?Task?ke?2
Pengerjaan?Task?Task?ke?4
Pengerjaan?Task?Task?ke?5
Pengerjaan?Task?Task?ke?9
Pengerjaan?Task?Task?ke?8
Pengerjaan?Task?Task?ke?7
Pengerjaan?Task?Task?ke?6
Process?finished?with?exit?code?0
從上面的代碼輸出中可以看出,由于提供的線程數(shù)為 6,因此該過程是異步執(zhí)行的。例如,如果我們創(chuàng)建一個(gè) 1 的線程池,則結(jié)果始終如下所示。
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?0
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?1
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?2
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?3
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?4
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?5
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?6
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?7
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?8
Sebuah?task?sudah?di?tambahkan?dengan?nama?Task?ke?9
Maksimun?thread?yang?terjadi?adalah?1
Pengerjaan?Task?Task?ke?0
Pengerjaan?Task?Task?ke?1
Pengerjaan?Task?Task?ke?2
Pengerjaan?Task?Task?ke?3
Pengerjaan?Task?Task?ke?4
Pengerjaan?Task?Task?ke?5
Pengerjaan?Task?Task?ke?6
Pengerjaan?Task?Task?ke?7
Pengerjaan?Task?Task?ke?8
Pengerjaan?Task?Task?ke?9
Process?finished?with?exit?code?0
因?yàn)橹挥?1 個(gè)池可用,所以該過程是同步完成的。
main.go
package?main
import?(
???"fmt"
???"runtime"
)
func?main()?{
???numberOfCPU?:=?runtime.NumCPU()
???runtime.GOMAXPROCS(numberOfCPU)
???/*?Jumlah?bilangan?prima?yang?akan?di?generate
????*/
???const?maxNumber?=?30
???ch?:=?make(chan?int)
???defer?close(ch)
???go?Generate(ch)
???for?i?:=?0;?i???????fmt.Println("Urutan?loop??ke?:?",i+1)
??????prime?:=?<-ch
??????fmt.Println("Angka?bilangan?prima?hasil?generate?adalah?",?prime)
??????ch1?:=?make(chan?int)
??????go?Filter(ch,?ch1,?prime)
??????ch?=?ch1
???}
}
func?Generate(ch?chan<-?int)?{
???for?i?:=?2;?;?i++?{
??????ch?<-?i
???}
}
func?Filter(in?<-chan?int,?out?chan<-?int,?prime?int)?{
???for?{
??????i?:=?<-in
??????if?i%prime?!=?0?{
?????????out?<-?i
??????}
???}
}
如果我們執(zhí)行上面的 golang 代碼,將獲得以下輸出。
Urutan?loop??ke?:??1
Angka?bilangan?prima?hasil?generate?adalah??2
Urutan?loop??ke?:??2
Angka?bilangan?prima?hasil?generate?adalah??3
Urutan?loop??ke?:??3
Angka?bilangan?prima?hasil?generate?adalah??5
Urutan?loop??ke?:??4
Angka?bilangan?prima?hasil?generate?adalah??7
Urutan?loop??ke?:??5
Angka?bilangan?prima?hasil?generate?adalah??11
Urutan?loop??ke?:??6
Angka?bilangan?prima?hasil?generate?adalah??13
Urutan?loop??ke?:??7
Angka?bilangan?prima?hasil?generate?adalah??17
Urutan?loop??ke?:??8
Angka?bilangan?prima?hasil?generate?adalah??19
Urutan?loop??ke?:??9
Angka?bilangan?prima?hasil?generate?adalah??23
Urutan?loop??ke?:??10
Angka?bilangan?prima?hasil?generate?adalah??29
Urutan?loop??ke?:??11
Angka?bilangan?prima?hasil?generate?adalah??31
Urutan?loop??ke?:??12
Angka?bilangan?prima?hasil?generate?adalah??37
Urutan?loop??ke?:??13
Angka?bilangan?prima?hasil?generate?adalah??41
Urutan?loop??ke?:??14
Angka?bilangan?prima?hasil?generate?adalah??43
Urutan?loop??ke?:??15
Angka?bilangan?prima?hasil?generate?adalah??47
Urutan?loop??ke?:??16
Angka?bilangan?prima?hasil?generate?adalah??53
Urutan?loop??ke?:??17
Angka?bilangan?prima?hasil?generate?adalah??59
Urutan?loop??ke?:??18
Angka?bilangan?prima?hasil?generate?adalah??61
Urutan?loop??ke?:??19
Angka?bilangan?prima?hasil?generate?adalah??67
Urutan?loop??ke?:??20
Angka?bilangan?prima?hasil?generate?adalah??71
Urutan?loop??ke?:??21
Angka?bilangan?prima?hasil?generate?adalah??73
Urutan?loop??ke?:??22
Angka?bilangan?prima?hasil?generate?adalah??79
Urutan?loop??ke?:??23
Angka?bilangan?prima?hasil?generate?adalah??83
Urutan?loop??ke?:??24
Angka?bilangan?prima?hasil?generate?adalah??89
Urutan?loop??ke?:??25
Angka?bilangan?prima?hasil?generate?adalah??97
Urutan?loop??ke?:??26
Angka?bilangan?prima?hasil?generate?adalah??101
Urutan?loop??ke?:??27
Angka?bilangan?prima?hasil?generate?adalah??103
Urutan?loop??ke?:??28
Angka?bilangan?prima?hasil?generate?adalah??107
Urutan?loop??ke?:??29
Angka?bilangan?prima?hasil?generate?adalah??109
Urutan?loop??ke?:??30
Angka?bilangan?prima?hasil?generate?adalah??113
Process?finished?with?exit?code?0
從上面的代碼中,可以在 go 例程中運(yùn)行方法的命令,即可將 go 命令添加到要處理的方法的前面。
這是 Golang 和 Java 如何在并發(fā)上實(shí)現(xiàn)的比較。我們不討論哪一個(gè)具有更好的性能。Go和Java編程語言各有優(yōu)缺點(diǎn)。
原文鏈接:https://medium.com/the-legend/golang-vs-java-concurrency-351ca5a845cb
推薦閱讀
