Java 和 Go 在并發(fā)實(shí)現(xiàn)中的區(qū)別
我一直想討論 Golang 和 Java,許多朋友都希望討論下。而我碰巧有相當(dā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)很長時(shí)間,因?yàn)闀?huì)發(fā)生隊(duì)列并且這些工作人員都已耗盡。為了處理這些許多請(qǐng)求,解決方案是增加額外的工作人員,以便可以同時(shí)執(zhí)行工作流程,并更快地為訪問者的請(qǐng)求提供服務(wù)。
它與并行性的概念不同,并行性有時(shí)會(huì)與并發(fā)性概念混淆。并行處理是解決大問題的一種方法,通常這樣做會(huì)花費(fèi)很長時(shí)間。通過將解決方案分成更小的部分來完成解決方案。這些小任務(wù)是獨(dú)立的,互不影響,并且同時(shí)完成。
在并行編程技術(shù)中,必須存在并發(fā),但是并發(fā)并不一定意味著存在并行進(jìn)程。
并發(fā)與并行的區(qū)別
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 < maxNumber; 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
本文轉(zhuǎn)載自微信公眾號(hào)「幽鬼」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系幽鬼公眾號(hào)。