添加goroutine
    //添加一个goroutine
    func main(){
    go func(){ // 通过go关键字来修饰函数来启动一个gotoutine
    fmt.Println(“sub goroutine”)
    }() //调用匿名函数
    }

    计数信号量
    wg sync.WaitGroup // go中的计数信号量
    wg.Add(2) // 添加两个量
    // goroutine中通过调用Done来释放信号量
    go func(){
    defer wg.Done()
    }
    func main(){
    wg.Wait() //阻塞等待所有goroutine运行完毕
    fmt.Println(“all done!”)
    }

    对共享资源加锁可以来避免竞争
    1. 原子函数
    原子函数能够以很底层的加锁机制来同步访问整型变量和指针
    import sync/atomic
    var counter int64
    for count:=0;count<3;count++{

    1. // 强制同一时刻只能有一个goroutine来运行并完成加法操作<br /> atomic.AddInt64(&counter,1)// 安全的对conuter加一<br /> /*<br /> atomic.LoadInt64(&varib) // 安全地读一个int64<br /> atomic.StoreInt64(&varib, v) // 安全地写一个int64
    2. */<br /> runtime.Gosched() //从当前线程退出,让给其他goroutine<br />}

    2. 使用互斥锁(mutex)来同步
    go 语言提供了两种锁类型sync.Mutex和sync.RWMutex
    Mutex 是最简单的锁,比较暴力,当一个goroutine获得Mutex后,其他goroutine只能等到其释放Mutex
    RWMutex相对友好些,是经典的单写多读模型,当读锁占用时会阻止写,但不阻止读,也就是多个goroutine可以同时获取读锁(调用RLock() ) ; 而写锁会阻止任何goroutine( 无论读还是写) 进来,相当于独占锁

    互斥锁用于在代码上创建一个临界区,保证同一时间只有一个goroutine可以执行这个临界区代码
    package main

    import (
    “fmt”
    “runtime”
    “sync”
    )
    var(
    counter int
    wg sync.WaitGroup
    mutex sync.Mutex
    )
    func main() {
    // server := NewServer(“127.0.0.1”, 8888)
    // server.Start()
    //计数加2,标识要等待两个goroutine
    wg.Add(2)
    go incCounter(1)
    go incCounter(2)
    wg.Wait()
    fmt.Println(“final counter:”,counter)
    }
    func incCounter(id int){
    defer wg.Done()
    for count:=0;count<2;count++{
    //统一时刻只允许一个goroutine进入临界区
    mutex.Lock()
    {
    value:=counter
    runtime.Gosched()
    value++
    counter=value
    }
    mutex.Unlock()//释放锁
    }
    }

    go语言可以通过竞争检测器来编译程序
    go build -race