当前位置: 首页 > 编程日记 > 正文

【go同步编程】

互斥锁

函数write中的这条defer语句保证了在该函数被执行结束之前互斥锁mutex一定会被解锁。

var mutex sync.Mutex
func write() {
mutex.Lock()
defer mutex.Unlock()
// 省略若干条语句
}
func repeatedlyLock() {var mutex sync.Mutexfmt.Println("Lock the lock. (G0)")mutex.Lock()fmt.Println("The lock is locked. (G0)")for i := 1; i <= 3; i++ {//开启3个协程,mutex已经锁定,所以程序会被阻塞。在unlock之后,随机启动一个。go func(i int) {//协程阻塞,只打印这一行。fmt.Printf("Lock the lock. (G%d)\n", i)mutex.Lock()fmt.Printf("The lock is locked. (G%d)\n", i)}(i)}time.Sleep(time.Second)fmt.Println("Unlock the lock. (G0)")mutex.Unlock()fmt.Println("The lock is unlocked. (G0)")time.Sleep(time.Second)
}

虽然互斥锁可以被直接的在多个Goroutine之间共享,但是我们还是强烈建议把对同一个互斥锁的成对的锁定和解锁操作放在同一个层次的代码块中。例如,在同一个函数或方法中对某个互斥锁的进行锁定和解锁。又例如,把互斥锁作为某一个结构体类型中的字段,以便在该类型的多个方法中使用它。

读写锁

  • 多个写操作之间都是互斥的.
  • 写操作与读操作之间也都是互斥的.
  • 多个读操作之间却不存在互斥关系.
func (*RWMutex) Lock //写锁定
func (*RWMutex) Unlock //写解锁
func (*RWMutex) RLock //读锁定
func (*RWMutex) RUnlock //读解锁

对于同一个读写锁来说,施加在它之上的读锁定可以有多个。因此,只有我们对互斥锁进行相同数量的读解锁,才能够让某一个相应的写锁定获得进行的机会。*sync.RWMutex类型都没有相应的方法让我们获得已进行的读锁定的数量,所以这里是很容易出现问题的。还好我们可以使用defer语句来尽量避免此类问题的发生。

package main
import ("sync""time"
)var m *sync.RWMutex
func main() {m = new(sync.RWMutex)//可以多个同时读go read(1)go read(2)time.Sleep(2 * time.Second)
}
func read(i int) {println(i, "read start")m.RLock()println(i, "reading")time.Sleep(1 * time.Second)m.RUnlock()println(i, "read end")
}
package main
import ("sync""time"
)
var m *sync.RWMutex
func main() {m = new(sync.RWMutex)//写的时候啥都不能干go write(1)go read(2)go write(3)time.Sleep(4 * time.Second)
}
func read(i int) {println(i, "read start")m.RLock()println(i, "reading")time.Sleep(1 * time.Second)m.RUnlock()println(i, "read end")
}
//1 write end结束之后,2才能reading
//2 read end结束之后,3 才能writing
func write(i int) {println(i, "write start")m.Lock()println(i, "writing")time.Sleep(1 * time.Second)m.Unlock()println(i, "write end")
}

条件变量

  • 等待通知: wait
    阻塞当前线程,直到收到该条件变量发来的通知。
  • 单发通知: signal
    让该条件变量向至少一个正在等待它的通知的线程发送通知,表示共享数据的状态已经改变。
  • 广播通知: broadcast
    让条件变量给正在等待它的通知的所有线程都发送通知。
var productCount inttype Factory struct {locker *sync.Mutexcond   *sync.Condgoods  []int
}//
func (self *Factory) init() {self.locker = &sync.Mutex{}self.cond = sync.NewCond(self.locker)
}//生产
func (self *Factory) product() {self.cond.L.Lock()defer self.cond.L.Unlock()productCount++self.goods = append(self.goods, productCount)self.cond.Signal()fmt.Println("发信号 ==")
}//消费
func (self *Factory) consume() {self.cond.L.Lock()defer self.cond.L.Unlock()for {if len(self.goods) == 0 {fmt.Println("睡了 =>")self.cond.Wait()fmt.Println("醒了 <=")} else {break}}fmt.Println(self.goods[0])self.goods = self.goods[1:]
}//消费流水线
func (self *Factory) assemblyLine1() {for {self.consume()time.Sleep(time.Millisecond * time.Duration(rand.Int63n(100)))}
}//生产流水线
func (self *Factory) assemblyLine0() {for {self.product()time.Sleep(time.Millisecond * time.Duration(rand.Int63n(200)))}
}func main() {runtime.GOMAXPROCS(1)var factory = &Factory{}factory.init()go factory.assemblyLine0()go factory.assemblyLine1()select {}
}

原子操作

参考csdn

增或减

函数名称都以Add为前缀,并后跟针对的具体类型的名称。

被操作的类型只能是数值类型

  • int32,int64,uint32,uint64,uintptr类型可以使用原子增或减操作
  • 第一个参数值必须是一个指针类型的值,以便施加特殊的CPU指令
  • 第二个参数值的类型和第一个被操作值的类型总是相同的。
func main(){var i32 int32fmt.Println("=====old i32 value=====")fmt.Println(i32)//第一个参数值必须是一个指针类型的值,因为该函数需要获得被操作值在内存中的存放位置,以便施加特殊的CPU指令//结束时会返回原子操作后的新值newI32 := atomic.AddInt32(&i32,3)fmt.Println("=====new i32 value=====")fmt.Println(i32)fmt.Println(newI32)var i64 int64fmt.Println("=====old i64 value=====")fmt.Println(i64)newI64 := atomic.AddInt64(&i64,-3)fmt.Println("=====new i64 value=====")fmt.Println(i64)fmt.Println(newI64)//=====old i32 value=====//0//=====new i32 value=====//3//3//=====old i64 value=====//0//=====new i64 value=====//-3//-3
}

比较并交换CAS

Compare And Swap 简称CAS,在sync/atomic包种,这类原子操作由名称以‘CompareAndSwap’为前缀的若干个函数代表。

func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)

载入Load

存储Store

交换Swap

waitGroup

WaitGroup用于线程同步,WaitGroup等待一组线程集合完成,才会继续向下执行。 主线程(goroutine)调用Add来设置等待的线程(goroutine)数量。 然后每个线程(goroutine)运行,并在完成后调用Done。 同时,Wait用来阻塞,直到所有线程(goroutine)完成才会向下执行。

  • Add()
  • Done()
  • Wait()
package main
import ("fmt""sync"
)
func main() {var wg sync.WaitGroupvar urls = []string{"http://www.golang.org/","http://www.google.com/","http://www.somestupidname.com/",}for _, url := range urls {// Increment the WaitGroup counter.wg.Add(1)go func(url string) {// Launch a goroutine to fetch the URL.defer wg.Done()// Fetch the URL.fmt.Println(url)}(url)}// Wait for all goroutines to finish.wg.Wait()fmt.Println("Game Over")
}

临时对象池

Pool用于存储那些被分配了但是没有被使用,而未来可能会使用的值,以减小垃圾回收的压力。
sync.Pool有两个公开的方法。一个是Get,另一个是Put。前者的功能是从池中获取一个interface{}类型的值,而后者的作用则是把一个interface{}类型的值放置于池中。

// 一个[]byte的对象池,每个对象为一个[]byte
var bytePool = sync.Pool{New: func() interface{} {b := make([]byte, 1024)return &b},
}func main() {a := time.Now().Unix()// 不使用对象池for i := 0; i < 1000000000; i++{obj := make([]byte,1024)_ = obj}b := time.Now().Unix()// 使用对象池for i := 0; i < 1000000000; i++{obj := bytePool.Get().(*[]byte)//TODO 这里的*[]byte,不太懂什么意思,猜测:返回的interface{}类型由*[]byte实现_ = objbytePool.Put(obj)}c := time.Now().Unix()fmt.Println("without pool ", b - a, "s")fmt.Println("with    pool ", c - b, "s")
}// without pool  34 s
// with    pool  24 s

对象池使用是较简单的,但原生的sync.Pool有个较大的问题:我们不能自由控制Pool中元素的数量,放进Pool中的对象每次GC发生时都会被清理掉。这使得sync.Pool做简单的对象池还可以,但做连接池就有点心有余而力不足了,比如:在高并发的情景下一旦Pool中的连接被GC清理掉,那每次连接DB都需要重新三次握手建立连接,这个代价就较大了。

相关文章:

Linux环境PHP7.0安装

PHP7和HHVM比较PHP7的在真实场景的性能确实已经和HHVM相当, 在一些场景甚至超过了HHVM。HHVM的运维复杂, 是多线程模型, 这就代表着如果一个线程导致crash了, 那么整个服务就挂了, 并且它不会自动重启。另外它采用JIT, 那么意味着, 重启以后要预热, 没有预热的情况下, 性能较为…

myeclipse java可视化_使用MyEclipse可视化开发Hibernate实例

使用MyEclipse可视化开发Hibernate实例2.7节的例子源代码在配套光盘sourcecode/workspace目录的chapter02_first项目中。这个实例主要演示如何使用MyEclipse的可视化开发工具开发Hibernate应用&#xff0c;利用MyEclipse可以提高我们开发Java EE应用的效率。操作的数据库表还是…

day20 文件上传下载

2019独角兽企业重金招聘Python工程师标准>>> 文件上传基础及api解析&#xff1a; 文件上传最终版&#xff1a; 文件下载&#xff1a; 转载于:https://my.oschina.net/u/2356966/blog/648774

腾讯开源基于 mmap 的高性能 key-value 组件 MMKV

腾讯微信团队宣布开源 MMKV &#xff0c;这是基于 mmap 内存映射的 key-value 组件&#xff0c;底层序列化/反序列化使用 protobuf 实现&#xff0c;主打高性能和稳定性。MMKV 从 2015 年中至今&#xff0c;在 iOS 微信上使用已有近 3 年&#xff0c;其性能和稳定性经过了时间的…

Linux环境thinkphp配置以及数据源驱动修改

项目中需要用到thinkphp&#xff0c;以下简称tp。linux版本&#xff1a;64位CentOS 6.4 Nginx版本&#xff1a;nginx1.8.0 php版本&#xff1a;php5.5.28 thinkphp版&#xff1a;3.2.31.安装LNMP Linux环境Nginx安装与调试以及PHP安装2.项目框架 tp源码下载http://www.thinkphp…

《Linux内核设计与实现》读书笔记 第三章 进程管理

第三章进程管理 进程是Unix操作系统抽象概念中最基本的一种。我们拥有操作系统就是为了运行用户程序&#xff0c;因此&#xff0c;进程管理就是所有操作系统的心脏所在。 3.1进程 概念&#xff1a; 进程&#xff1a;处于执行期的程序。但不仅局限于程序&#xff0c;还包含其他资…

java持续集成soapui_集成testNG到JavaAPI测试-执行多条用例

*****************************************************************在这门课里你将学到Web Services(SOAP WebService和REST API)的手动测试及自动化测试&#xff0c;熟练使用Groovy脚本自动化测试WebService。这门课程设计的是从零基础入门开始学&#xff0c;然后以循序渐进…

python-os

os.listdir(path):path-->路径 返回类型为listos.getcwd() 获取当前工作目录os.chdir() 切换工作目录os.mkdir() 新建目录os.path.exists()os.path.isdir() os.path.join() 拼接字符串路径os.path.exists(rpath) 判断路径是否存在 r原始路径os.path.isdir() 判断是否是文件夹…

NetBeans配置Xdebug 远程调试PHP

很多PHP程序员使用echo&#xff0c;dump等比较原始的方法调试&#xff0c;这是非常落后的。几年前本人写过一篇&#xff1a; NetBeans配置Xdebug 由于那篇文档还需要引用本人写的其他文档&#xff0c;感觉有些分散&#xff0c;所以这里重新写一篇完整的。linux版本&#xff1a;…

java自定义上下文对象_Java框架_Spring应用上下文对象加载配置

我们都知道IOC是spring框架的核心&#xff0c;主要作用是控制反转&#xff0c;把我们需要的对象从容器中提供给我们&#xff0c;但是IOC是如何加载我们所需要的对象的&#xff1f;Spring容器是IOC容器的一种&#xff0c;它通过ApplicationContext接口将我们所需要的配置文件进行…

ThreadLocal源码分析

ThreadLocal的作用 Java对象是线程间共享的&#xff0c;但有时我们需要一些线程间隔离的对象&#xff0c;该对象只能由同一个线程读写&#xff0c;对其他线程不可见。ThreadLocal正式提供了这样的机制&#xff0c;详细使用方式请参考Java ThreadLocal。 ThreadLocal实现原理 自…

远程连接windows出现身份验证错误,提示由于CredSSP加密Oracle修正解决方案

本机操作系统(OS版本:10.0.17134) 远程计算机操作系统&#xff08;OS版本:6.3.9600&#xff09; 远程连接的时候报错“出现身份验证错误&#xff0c;要求的函数不受支持。远程计算机:xxx 这可能是由于CredSSP加密Oracle修正,若要了解详细信息...” 原因是系统更新安装了补丁&am…

MediaWiki安装

MediaWiki可以方便的让你搭建自己的wiki&#xff0c;公司内部使用非常方便官网&#xff1a; https://www.mediawiki.org/wiki/MediaWiki安装MediaWiki的必要环境 PHPMysql 下载最新版解压即可 # tar -xzvf mediawiki-1.25.2.tar.gz # mv mediawiki-1.25.2 wiki 输入首页引导一…

sql的四种连接 用mysql的语句写_170221、浅谈mysql的SQL的四种连接

例子&#xff1a;-------------------------------------------------a表 id name b表 id job parent_id1 张3 1 23 12 李四 2 34 23 王武 3 34 4a.id同parent_id 存在关…

MySQL冷备份的跨操作系统还原

数据来源&#xff1a;linux平台mysql版本为5.7 数据去向&#xff1a;windows平台mysql版本为5.7 操作步骤&#xff1a; 第一步&#xff1a;关闭mysql服务 service mysqld stop 第二步&#xff1a;归档linux平台下mysql的数据目录 tar -czvf data.tar.gz /usr/local/mysql/data …

Java 社区领袖联合发文:别慌,Java 仍然是免费的!

开发四年只会写业务代码&#xff0c;分布式高并发都不会还做程序员&#xff1f; >>> 在去年的 Java One 上&#xff0c;Mark Cavage 当时宣布 Oracle 将逐步开源 Oracle JDK 的专有功能&#xff08;商业特性&#xff09;。Oracle Java 平台产品管理高级总监 Donald …

Squid安装

最新版Squid安装 http://www.squid-cache.org/Versions/v3/3.5/# wget http://www.squid-cache.org/Versions/v3/3.5/squid-3.5.7.tar.gz# tar zxvf squid-3.5.7.tar.gz# cd squid-3.5.7# ./configure --prefix/usr/local/squid# make && make install# chmod -R 777 /…

Java内部类手机专卖店_JAVA——内部类的那些事儿

obj3.func();//3.2 访问静态内部类的静态方法(通过类名访问)Outer.StaInner.staFunc();//4 局部内部类访问局部变量Outer obj4 new Outer();obj4.local();//5 匿名内部类Outer obj5 new Outer();obj5.anonymous();//6 匿名内部类作为参数asPara(new AbstractClass() {public …

Linux下Postfix的配置和使用

Postfix为何物&#xff0c;详见&#xff1a;http://zh.wikipedia.org/wiki/Postfix 0.关于Postfix postfix的产生是为了替代传统的sendmail.相较于sendmail,postfix在速度。性能和稳定性上都更胜一筹。如今眼下许多的主流邮件服务事实上都在採用postfix. 当我们须要一个轻量级的…

部分人说 Java 的性能已经达到甚至超过 C++,是真的吗?

好多Java程序员都说由于JIT技术的引入&#xff0c;Java的性能已经和C一样了&#xff0c;而且Java的开发效率极高&#xff0c;可以省下60%的时间。请问事实真的是这样吗&#xff1f;我平常也都在写这两个语言&#xff0c;但是因为开发的软件的复杂度不大&#xff0c;并没有感觉到…

Wiki 开源软件

Wiki 是一个协同著作平台或称开放编辑系统。所谓协同工作&#xff0c; 即它能够让浏览网页的人都能够去修订网页&#xff0c;其简介的 ... Wiki 是怎么做到的. Wiki 使用 了简化的语法&#xff0c;替代复杂的HTML&#xff0c;加上WEB 界面的编辑工具&#xff0c;降低内容维护的…

Android studio安装与调试

1.下载安装android studio 下载好之后安装好2.启动报错提示1&#xff09;进入刚安装的Android Studio目录下的bin目录。找到idea.properties文件&#xff0c;用文本编辑器打开。2&#xff09;在idea.properties文件末尾添加一行&#xff1a; disable.android.first.runtrue &am…

java的父类java.lang.object_根父类:java.lang.Object

1、根父类(1)Object类型是所有引用数据类型的超类&#xff0c;包括数组类型如果一个类没有显式的声明它的父类&#xff0c;那么它的父类就是Object。(2)Object类中的方法&#xff0c;会继承到所有类型的对象中&#xff0c;包括数组对象。即所有对象都可以调用Object类中声明的方…

spring cloud服务发现注解之@EnableDiscoveryClient与@EnableEurekaClient

在使用服务发现的时候提到了两种注解&#xff0c;一种为EnableDiscoveryClient,一种为EnableEurekaClient,用法上基本一致&#xff0c;今天就来讲下两者&#xff0c;下文是从stackoverflow上面找到的对这两者的解释&#xff1a;原文链接 There are multiple implementations of…

strust2自定义interceptor的基本方法及操作

需求&#xff1a;制作一个网站需要用户登陆后才能查看&#xff0c;即一个权限的问题 1.首先明确在用户没登陆前有两个Action请求是可以通过的&#xff0c;即注册和登陆。 2.创建拦截器&#xff0c;如UserLoginInterceptor.java&#xff0c;如下 public class UserLoginIntercep…

使用xdebug分析thinkphp框架函数调用图

开发中需要性能调优&#xff0c;使用xdebug分析thinkphp框架函数调用图。关于xdebug的安装参考这2篇 NetBeans配置Xdebug 远程调试PHP php扩展xdebug安装以及用kcachegrind系统分析1.安装xdebug 需要先去http://www.xdebug.org看看一些文档&#xff0c;xdebug作为php扩展安装 #…

java+script+当前日期_如何在JavaScript中获取当前日期?

如何在JavaScript中获取当前日期&#xff1f;#1楼您可以使用扩展了 Date对象的Date.js库&#xff0c;从而可以使用.today()方法。#2楼如果您想对日期格式进行更多的粒度控制&#xff0c;我强烈建议您查看一下momentjs。 很棒的图书馆-只有5KB。 http://momentjs.com/#3楼你可以…

java中的类修饰符、成员变量修饰符、方法修饰符。

类修饰符&#xff1a; public&#xff08;访问控制符&#xff09;&#xff0c;将一个类声明为公共类&#xff0c;他可以被任何对象访问&#xff0c;一个程序的主类必须是公共类。 abstract&#xff0c;将一个类声明为抽象类&#xff0c;没有实现的方法&#xff0c;需要子类提供…

Linux 系统挂载数据盘

Linux 系统挂载数据盘&#xff1a; 适用系统&#xff1a;Linux&#xff08;Redhat , CentOS&#xff0c;Debian&#xff0c;Ubuntu&#xff09;* Linux的云服务器数据盘未做分区和格式化&#xff0c;可以根据以下步骤进行分区以及格式化操作。下面的操作将会把数据盘划分为一个…

java 启动某个类_java – Spring Boot – 如何指定备用启动类? (多个入口点)

我想添加一个替代的入口点到我的Spring-Boot应用程序.我宁愿把它当成一个肥罐.这可能吗&#xff1f;根据他们的documentation,属性loader.main指定要启动的主类的名称.我尝试java -jar MyJar.jar –loader.main com.mycompany.AlternateMain,但是我的pom.xml中指定的start-cla…