Go与Java Go和Java微观对比

简介: 本文对比了Go语言与Java在线程实现上的差异。Go通过Goroutines实现并发,使用`go`关键字启动;而Java则通过`Thread`类开启线程。两者在通信机制上也有所不同:Java依赖共享内存和同步机制,如`synchronized`、`Lock`及并发工具类,而Go采用CSP模型,通过Channel进行线程间通信。此外,文章还介绍了Go中使用Channel和互斥锁解决并发安全问题的示例。

Go语言中线程的实现和Java语言中线程的实现

 go中的线程相关的概念是Goroutines(并发),是使用go关键字开启。

Java中的线程是通过Thread类开启的。  

在go语言中,一个线程就是一个Goroutines,主函数就是(主) main Goroutines。  

使用go语句来开启一个新的Goroutines

比如:  

普通方法执行

scss

体验AI代码助手

代码解读

复制代码

 myFunction()

开启一个Goroutines来执行方法

scss

体验AI代码助手

代码解读

复制代码

 go myFunction()

java中是

scss

体验AI代码助手

代码解读

复制代码

 new Thread(()->{

 

 //新线程逻辑代码

 

 }).start();

参考下面的代码示例:

 

go

体验AI代码助手

代码解读

复制代码

package main


import (
   "fmt"
)


//并发开启新线程goroutine测试


//我的方法
func myFunction() {
   fmt.Println("Hello!!!")
}
//并发执行方法
func goroutineTestFunc() {
   fmt.Println("Hello!!! Start Goroutine!!!")
}




func main() {
   /*
   myFunction()
   //go goroutineTestFunc()
   //此时因为主线程有时候结束的快,goroutineTestFunc方法得不到输出,由此可以看出是开启了新的线程。
   */
   //打开第二段执行
   /*
   go goroutineTestFunc()
   time.Sleep(10*time.Second)//睡一段时间  10秒
   myFunction()
    */
}

 

线程间的通信:

java线程间通信有很多种方式:

比如最原始的 wait/notify

到使用juc下高并发线程同步容器,同步队列

到CountDownLatch等一系列工具类

 ......

甚至是分布式系统不同机器之间的消息中间件,单机的disruptor等等。

Go语言不同,线程间主要的通信方式是Channel。

Channel是实现go语言多个线程(goroutines)之间通信的一个机制。

Channel是一个线程间传输数据的管道,创建Channel必须声明管道内的数据类型是什么  

下面我们创建一个传输int类型数据的Channel  

代码示例:  

go

体验AI代码助手

代码解读

复制代码

package main


import "fmt"


func main() {
   ch := make(chan int)
   fmt.Println(ch)
}

 

channel是引用类型,函数传参数时是引用传递而不是值拷贝的传递。

 channel的空值和别的应用类型一样是nil。

==可以比较两个Channel之间传输的数据类型是否相等。  

channel是一个管道,他可以收数据和发数据。

具体参照下面代码示例:

go

体验AI代码助手

代码解读

复制代码

package main


import (
   "fmt"
   "time"
)
//channel发送数据和接受数据用 <-表示,是发送还是接受取决于chan在  <-左边还是右边
//创建一个传输字符串数据类型的管道
var  chanStr  = make(chan string)
func main() {
   fmt.Println("main goroutine print Hello ")
   //默认channel是没有缓存的,阻塞的,也就是说,发送端发送后直到接受端接受到才会施放阻塞往下面走。
   //同样接收端如果先开启,直到接收到数据才会停止阻塞往下走
   //开启新线程发送数据
   go startNewGoroutineOne()
   //从管道中接收读取数据
   go startNewGoroutineTwo()
   //主线程等待,要不直接结束了
   time.Sleep(100*time.Second)
}


func startNewGoroutineOne() {
   fmt.Println("send channel print Hello ")
   //管道发送数据
   chanStr <- "Hello!!!"
}


func startNewGoroutineTwo(){
   fmt.Println("receive channel print Hello ")
   strVar := <-chanStr
   fmt.Println(strVar)
}

 

无缓存的channel可以起到一个多线程间线程数据同步锁安全的作用。

缓存的channel创建方式是

make(chan string,缓存个数)  

缓存个数是指直到多个数据没有消费或者接受后才进行阻塞。

类似于java中的synchronized和lock  

可以保证多线程并发下的数据一致性问题。

首先我们看一个线程不安全的代码示例:

 

scss

体验AI代码助手

代码解读

复制代码

package main


import (
   "fmt"
   "time"
)


//多线程并发下的不安全问题
//金额
var moneyA int =1000
//添加金额
func subtractMoney(subMoney int) {
   time.Sleep(3*time.Second)
   moneyA-=subMoney
}


//查询金额
func getMoney() int {
   return moneyA;
}




func main() {


   //添加查询金额
   go func() {
      if(getMoney()>200) {
         subtractMoney(200)
         fmt.Printf("200元扣款成功,剩下:%d元\n",getMoney())
      }
   }()


   //添加查询金额
   go func() {
      if(getMoney()>900) {
         subtractMoney(900)
         fmt.Printf("900元扣款成功,剩下:%d元\n",getMoney())
      }
   }()
   //正常逻辑,只够扣款一单,可以多线程环境下结果钱扣多了
   time.Sleep(5*time.Second)
   fmt.Println(getMoney())
}

 

缓存为1的channel可以作为锁使用:

 

示例代码如下:

scss

体验AI代码助手

代码解读

复制代码

package main


import (
   "fmt"
   "time"
)


//多线程并发下使用channel改造
//金额
var moneyA  = 1000
//减少金额管道
var synchLock = make(chan int,1)


//添加金额
func subtractMoney(subMoney int) {
   time.Sleep(3*time.Second)
   moneyA-=subMoney
}


//查询金额
func getMoney() int {
   return moneyA;
}




func main() {


   //添加查询金额
   go func() {
      synchLock<-10
      if(getMoney()>200) {
         subtractMoney(200)
         fmt.Printf("200元扣款成功,剩下:%d元\n",getMoney())
      }
      <-synchLock
   }()


   //添加查询金额
   go func() {
      synchLock<-10
      if(getMoney()>900) {
         subtractMoney(900)
         fmt.Printf("900元扣款成功,剩下:%d元\n",getMoney())
      }
      synchLock<-10
   }()
   //这样类似于java中的Lock锁,不会扣多
   time.Sleep(5*time.Second)
   fmt.Println(getMoney())
}

 

go也有互斥锁

类似于java中的Lock接口

参考如下示例代码:

scss

体验AI代码助手

代码解读

复制代码

package main


import (
   "fmt"
   "sync"
   "time"
)


//多线程并发下使用channel改造
//金额
var moneyA  = 1000


var lock sync.Mutex;
//添加金额
func subtractMoney(subMoney int) {
   lock.Lock()
   time.Sleep(3*time.Second)
   moneyA-=subMoney
   lock.Unlock()
}


//查询金额
func getMoney() int {
   lock.Lock()
   result := moneyA
   lock.Unlock()
   return result;
}




func main() {
   //添加查询金额
   go func() {
      if(getMoney()>200) {
         subtractMoney(200)
         fmt.Printf("200元扣款成功,剩下:%d元\n",getMoney())
      }else {
         fmt.Println("余额不足,无法扣款")
      }
   }()


   //添加查询金额
   go func() {
      if(getMoney()>900) {
         subtractMoney(900)
         fmt.Printf("900元扣款成功,剩下:%d元\n",getMoney())
      }else {
         fmt.Println("余额不足,无法扣款")
      }
   }()
   //正常
   time.Sleep(5*time.Second)
   fmt.Println(getMoney())
}

转载来源:https://juejin.cn/post/7122435320318001166

相关文章
|
安全 Java Go
Java vs. Go:并发之争
【4月更文挑战第20天】
1046 1
|
8月前
|
人工智能 安全 Java
Go与Java泛型原理简介
本文介绍了Go与Java泛型的实现原理。Go通过单态化为不同类型生成函数副本,提升运行效率;而Java则采用类型擦除,将泛型转为Object类型处理,保持兼容性但牺牲部分类型安全。两种机制各有优劣,适用于不同场景。
365 24
|
8月前
|
JavaScript Java Go
Go、Node.js、Python、PHP、Java五种语言的直播推流RTMP协议技术实施方案和思路-优雅草卓伊凡
Go、Node.js、Python、PHP、Java五种语言的直播推流RTMP协议技术实施方案和思路-优雅草卓伊凡
618 0
|
算法 Java Go
运行时管理GO与Java的概要对比
【5月更文挑战第17天】本文介绍Go、Python和Java的运行时机制各异。Go是编译型语言,其runtime负责内存管理、GC和协程调度,强调性能和低延迟。Java的JVM兼顾跨平台和性能,使用字节码和JIT编译,其GC策略复杂且高效。三种语言在设计和优化上各有侧重,适用不同场景。
424 3
|
算法 Java Go
Go vs Java:内存管理与垃圾回收机制对比
对比了Go和Java的内存管理与垃圾回收机制。Java依赖JVM自动管理内存,使用堆栈内存并采用多种垃圾回收算法,如标记-清除和分代收集。Go则提供更多的手动控制,内存分配与释放由分配器和垃圾回收器协同完成,使用三色标记算法并发回收。示例展示了Java中对象自动创建和销毁,而Go中开发者需注意内存泄漏。选择语言应根据项目需求和技术栈来决定。
|
Java Go C#
编程语言C#、C++、Java、Python、go 选择哪个好?
我想说的是,不论选择哪种编程语言,决定选择的都是你最终的目的,做选择之前,先充分调研每一个选择项,再做选择思路就会非常清晰了。
596 3
|
JavaScript 前端开发 Java
Go语言入门【java->go】
Go语言入门【java->go】
173 2
|
Java 大数据 Go
Go vs Java:在大数据处理领域的性能对比
Go与Java在大数据处理中各有特点。Go启动快,内存占用少,静态类型及并发模型(goroutine和channel)使其在并发性能上有优势。Java虽然启动慢,JVM内存占用高,但拥有丰富的生态系统和并发工具。代码示例展示了Go的goroutine和Java的线程池处理大数据的场景。在性能上,Go可能更优,但Java的跨平台性和生态广度使其仍被广泛应用。
|
网络协议 物联网 Java
Go与Java:在物联网领域的适用性分析
本文对比分析了Go和Java在物联网领域的适用性。Go语言因其轻量级、高效和并发特性,适合资源受限的物联网设备,特别是处理并发连接和数据流。Java则凭借跨平台性、丰富的生态系统和企业级应用能力,适用于大型物联网系统和复杂业务场景。两者在物联网领域各有优势,开发者可根据项目需求选择合适的语言。
|
编解码 JavaScript 前端开发
【专栏】介绍了字符串Base64编解码的基本原理和在Java、Python、C++、JavaScript及Go等编程语言中的实现示例
【4月更文挑战第29天】本文介绍了字符串Base64编解码的基本原理和在Java、Python、C++、JavaScript及Go等编程语言中的实现示例。Base64编码将24位二进制数据转换为32位可打印字符,用“=”作填充。文中展示了各语言的编码解码代码,帮助开发者理解并应用于实际项目。
665 1