zoukankan      html  css  js  c++  java
  • Golang sync

    Go1.9.2 sync库里包含下面几类:Mutex/RWMutex/Cond/WaitGroup/Once/Map/Pool

     

    1.Mutex:互斥锁,等同于linux下的pthread_mutex_t

    //多个线程同时运行,获得Mutex锁者线程优先执行,其余线程阻塞等待
    func testMutex() {
        mutex := sync.Mutex{};
        for i := 0; i < 10; i++ {
            go func(idx int) {
                mutex.Lock();
                defer mutex.Unlock();
                fmt.Println("idx :=", idx);
                time.Sleep(time.Second);
            }(i)
        }
    
        time.Sleep(20 * time.Second);
        fmt.Println("Func finish.");
    }

     

    2.RWMutex:读写锁,等同于linux下的pthread_rwlock_t

    //写请求在读锁和写锁时都必须阻塞等待,读请求只在写锁时阻塞等待
    func testRWMutex() {
        rwMutex := sync.RWMutex{};
        for i := 0; i < 10; i++ {
            go func(idx int) {
                rwMutex.RLock();
                defer rwMutex.RUnlock();
                fmt.Println("Read Mutex :",idx);
            }(i);
    
            go func(idx int) {
                rwMutex.Lock();
                defer rwMutex.Unlock();
                fmt.Println("Write Mutex :",idx);
                time.Sleep(time.Second);
            }(i);
        }
    
        time.Sleep(20 * time.Second);
        fmt.Println("Func finish.");
    }

     

    3.Cond:条件变量,等同于linux下的pthread_cond_t

    func testCond() {
        cond := sync.NewCond(&sync.Mutex{});
    
        cond.L.Lock(); //①上锁
        defer cond.L.Unlock();
    
        go func() {
            fmt.Println("go wait lock.");
            cond.L.Lock(); //②等Wait解锁
    
            defer cond.L.Unlock(); //⑤解锁后触发Wait
            defer fmt.Println("go unlock.");
    
            fmt.Println("go locked.");
            cond.Signal(); //④触发Wait等待解锁
        }()
    
        time.Sleep(time.Second);
    
        fmt.Println("start wait.");
        for {
            cond.Wait(); //③可以理解为立刻解锁并触发一个阻塞线程(如果没有阻塞线程则不触发)后立刻再上锁等待Signal信号
            fmt.Println("wait finish.");
            break;
        }
    
        time.Sleep(time.Second);
        fmt.Println("Func finish.");
    }

     

    4.WaitGroup:组等待

    //Add 增加等待计数;Done减少等待计数;当计数为0时触发Wait;
    func testWaitGroup() {
        waitGroup := sync.WaitGroup{};
        for i := 0; i < 10; i++ {
            waitGroup.Add(1);
    
            go func(idx int) {
                time.Sleep(time.Second);
                fmt.Println("go : ", idx);
                waitGroup.Done();
            }(i)
        }
    
        for{
            fmt.Println("start wait.");
            waitGroup.Wait();
            fmt.Println("wait finish.");
            break;
        }
    
        time.Sleep(time.Second);
        fmt.Println("Func finish.");
    }

     

    5.Once:只执行一次

    //只执行一次以后不再触发
    func testOnce() {
        once := sync.Once{};
        for i := 0; i < 10; i++ {
            go func(idx int) {
                once.Do(func() {
                    fmt.Println("Do once : ", idx); //这里只执行一次
                })
    
                fmt.Println("go : ", idx);
            }(i)
        }
    
        time.Sleep(5 * time.Second);
        fmt.Println("Func finish.");
    }

     

    6.Map:线程安全map

    func testMap() {
        syncMap := sync.Map{};
        for i := 0; i < 10; i++ {
            go func(idx int) {
                //如果没有则保存起来
                _, ok := syncMap.LoadOrStore(idx, " StrVal = "+strconv.FormatInt(int64(idx), 10));
                if !ok {
                    fmt.Println("Store idx = ",idx);
                }
            }(i)
    
            go func(idx int) {
                val, ok := syncMap.Load(idx);
                if ok {
                    fmt.Println("Load success idx = ", idx, val);
                } else {
                    fmt.Println("Load fail idx = ", idx)
                }
            }(i)
    
        }
    
        time.Sleep(5 * time.Second);
        fmt.Println("Func finish.");
    }

     

    7.Pool:线程安全对象池

    func testPool() {
        p := &sync.Pool{
            New: func() interface{} {
                return -1;
            },
        }
    
        for i := 0; i < 10; i++ {
            go func(idx int) {
                p.Put(idx);
            }(i)
        }
        
        //取出来的对象是无序的
        for i := 0; i < 20; i++ {
            go func() {
                val := p.Get();
                fmt.Println("Get val = ", val);
            }()
        }
    
        time.Sleep(5 * time.Second);
        fmt.Println("Func finish.");
    }

     使用Pool一定要注意一下问题:

    1.用途仅仅是增加对象重用的几率,减少gc的负担,而开销方面也不是很便宜的。

    2.GC会将Pool清理掉。

    3.Get不能保证将Put进去的全部取出来!如下例子:

    func testPoolPutGet(){
        myPool := &sync.Pool{
            New: func() interface{} {
                return 0;
            },
        }
    
        myPool.Put(1) //放入1
        myPool.Put(2) //放入2
    
        time.Sleep(time.Second)
    
        p1 := myPool.Get().(int)
        fmt.Println(p1) // 获得2
    
        p2 := myPool.Get().(int)
        fmt.Println(p2) // 获得0,而不是1!
    }

    4.关于Pool的实现原理,可以参考《go语言的官方包sync.Pool的实现原理和适用场景》

    以上。

  • 相关阅读:
    Nginx 部署多个 web 项目(虚拟主机)
    Nginx 配置文件
    Linux 安装 nginx
    Linux 安装 tomcat
    Linux 安装 Mysql 5.7.23
    Linux 安装 jdk8
    Linux 安装 lrzsz,使用 rz、sz 上传下载文件
    springMVC 拦截器
    spring 事务
    基于Aspectj 注解实现 spring AOP
  • 原文地址:https://www.cnblogs.com/chevin/p/8083022.html
Copyright © 2011-2022 走看看