go - 线程从 java 到 go

标签 go

我怎样才能将下面的代码翻译成 Go,你可以在下面看到我的尝试,但是因为我在等待按键输入,所以代码总是返回 20000,其中java会输出不同的结果。我知道两者都有竞争条件,但我只想知道翻译。

Java

public class Counting {
    public static void main(String[] args) throws InterruptedException {
      class Counter {
        private int count = 0;
        public void increment() { ++count; }
        public int getCount() { return count; }
      }
    final Counter counter = new Counter();

    class CountingThread extends Thread {
        public void run() {
            for(int x = 0; x < 10000; ++x)
                counter.increment();    
        }
    }

    CountingThread t1 = new CountingThread();
    CountingThread t2 = new CountingThread();
    t1.start(); t2.start();
    t1.join(); t2.join();
    System.out.println(counter.getCount());
  }
}

这是我的尝试:

import (
  "fmt"
)

type Counting struct {
  count int
}

var counter = Counting{}

func (c *Counting) increment() {
  c.count++
}

func (c *Counting) getCount() int {
  return c.count
}

func CountingThread() {
  for i := 0; i < 10000; i++ {
    counter.increment()
  }
}

func main() {
  go CountingThread()
  go CountingThread()
  var input string
  fmt.Scanln(&input)
  fmt.Println(counter.getCount())
}

最佳答案

Goroutine 不是线程,因此必须使用同步原语。

您的翻译应该使用 sync.WaitGroup 完成(参见 http://golang.org/pkg/sync/#WaitGroup )。

package main

import (
    "fmt"
    "sync"
)

type Counting struct {
    count int
}

var counter = Counting{}

func (c *Counting) increment() {
    c.count++
}

func (c *Counting) getCount() int {
    return c.count
}

func CountingThread(wg *sync.WaitGroup) {
    for i := 0; i < 10000; i++ {
        counter.increment()
    }
    wg.Done() // mark the goroutine as finished
}

func main() {
    var wg sync.WaitGroup

    wg.Add(2) // we know we'll wait for 2 goroutines

    go CountingThread(&wg)
    go CountingThread(&wg)

    wg.Wait() // wait for the goroutines to both finish

    fmt.Println(counter.getCount())
}

此处演示:http://play.golang.org/p/0SHCvowDjI

它输出“预期”值 20000。

显然这段代码演示了数据竞争:

$ go run -race race.go 
==================
WARNING: DATA RACE
Read by goroutine 6:
  main.CountingThread()
      race.go:24 +0x48

Previous write by goroutine 7:
  main.CountingThread()
      race.go:24 +0x5e

Goroutine 6 (running) created at:
  main.main()
      race.go:34 +0x8f

Goroutine 7 (running) created at:
  main.main()
      race.go:35 +0xb1
==================
19042
Found 1 data race(s)
exit status 66

这可以通过使用原子计数器来解决:

type Counting struct {
        count int32
}

var counter = Counting{}

func (c *Counting) increment() {
        atomic.AddInt32(&c.count, 1)
}

func (c *Counting) getCount() int32 {
        return atomic.LoadInt32(&c.count)
}

参见 http://play.golang.org/p/68FkSWt6rw 的演示.

关于go - 线程从 java 到 go,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32369824/

相关文章:

sql - 从准备好的语句中检索值并在 Go 中选择查询

go - Glide 管理的依赖项如何与构建一起工作?

go - 在 gorilla/mux 框架中使用 Go routines

go - 链接 CAS 中间件和 httprouter() 路由

postgresql - IN pq.Array 传递值失败

javascript - 将结构数组传递给HTML模板以填充下拉列表

azure - 使用 Go Task 的 Yaml Azure 管道安装 Terratest 时出现问题 - 在子文件夹中触发 terratest 测试时出现问题

go - os.PathError 未实现错误

linux - 在 Ubuntu 核心上安装 Go 编程语言 (snappy)

go - 在 Go 中使用外部 API 后使用 REST 客户端保存数据