go语言的成神之路-筑基篇-对文件的操作
目录
一、对文件的读写
Reader 接口
Writer接口
copy接口
bufio的使用
ioutil库
二、cat命令
三、包
1. 包的声明
2. 导入包
3. 包的可见性
4. 包的初始化
5. 标准库包
6. 第三方包
7. 包的组织
8. 包的别名
9. 包的路径
10. 包的版本管理
四、go mod
1. 初始化一个新的模块
2. 依赖管理
3. 查看依赖关系
4. 下载依赖
5. 清理未使用的依赖
6. 替换依赖
7. 版本管理
8. 私有模块
9. 构建和测试
10. 示例
总结
一、对文件的读写
在 Go 语言中,io
包提供了基本的接口,用于 I/O 原语。它的主要目的是将这些原语抽象化,使得它们在不同的实现中可以通用。
Reader
接口
以下是一个对文件中内容读取的一个示例:
package mainimport ("fmt""io""os"
)func main() {// 打开文件 text.txt,如果打开失败,打印错误信息并返回file, err := os.Open("./text.txt")if err != nil {fmt.Println(err)return}// 确保文件在函数结束时关闭defer file.Close()// 定义一个长度为 128 的字节数组作为缓冲区var buf [128]byte// 存储文件内容的字节切片var content []bytefor {// 从文件中读取数据到缓冲区,n 表示读取的字节数n, err := file.Read(buf[:])// 如果到达文件末尾,跳出循环if err == io.EOF {break}// 如果读取过程中出现错误,打印错误信息并返回if err != nil {fmt.Println(err)return}// 将读取到的数据添加到 content 切片中content = append(content, buf[:n]...)}// 将字节切片转换为字符串并打印fmt.Println(string(content))
}
Writer接口
以下是写入文件的操作:
注:每次写入的时候原文件中的内容都会被覆盖。
// Writer接口的定义和实现
package mainimport ("fmt""os"
)func main() {// 打开文件 text.txt,如果文件不存在则创建,如果文件存在则清空内容file, err := os.Create("./text2.txt")if err != nil {fmt.Println(err)return}// 确保文件在函数结束时关闭defer file.Close()// 定义一个字符串str := "Hello,World!"// 将字符串转换为字节切片data := []byte(str)// 将字节切片写入文件_, err = file.Write(data)// 如果写入过程中出现错误,打印错误信息并返回if err != nil {fmt.Println(err)return}
}
写入一个 Hello,World!
写入一个”你好世界!“
可以看出原来文件中的文本被替换了。
copy接口
以下是复制文件的操作:
// io.Copy的使用
package mainimport ("fmt""io""os"
)func main() {// 打开文件 text.txt,如果文件不存在则创建,如果文件存在则清空内容begin, err := os.Open("./text2.txt")if err != nil {fmt.Println(err)return}// 确保文件在函数结束时关闭defer begin.Close()// 打开文件 text2.txt,如果文件不存在则创建,如果文件存在则清空内容end, err := os.Create("./text3.txt")if err != nil {fmt.Println(err)return}// 确保文件在函数结束时关闭defer end.Close()// 将文件 text.txt 的内容复制到文件 text2.txt 中_, err = io.Copy(end, begin)// 如果复制过程中出现错误,打印错误信息并返回if err != nil {fmt.Println(err)return}
}
begin中的内容会自动覆盖end中的内容。
bufio的使用
常见的方法如下:
// bufio的使用
package mainimport ("bufio""fmt""io""os"
)func wr() {// 参数2 是文件的打开方式,os.O_CREATE|os.O_WRONLY|os.O_APPEND 表示创建文件并以写入模式打开,文件不存在则创建,文件存在则在文件末尾追加内容// 参数3 是文件的权限,0666 表示文件所有者、组和其他用户都有读写权限// w写 r读 a追加 x执行file, err := os.OpenFile("./text.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)if err != nil {fmt.Println(err)return}defer file.Close()// 获取writer对象writer := bufio.NewWriter(file)writer.WriteString("hello bufio")// 刷新缓冲区writer.Flush()
}func rd() {file, err := os.Open("./text.txt")if err != nil {fmt.Println(err)return}defer file.Close()reader := bufio.NewReader(file)for {line, _, err := reader.ReadLine()if err != io.EOF {fmt.Println(err)break}if err != nil {fmt.Println(err)return}fmt.Println(string(line))}
}func main() {wr()
}
以这种方式进行读写不会覆盖原来的文件
读取文本文件的时候是按行读取的
ioutil库
// ioutil的使用
package mainimport ("fmt""io/ioutil"
)func wr() {err := ioutil.WriteFile("./text.txt", []byte("hello ioutil"), 0666)if err != nil {fmt.Println(err)return}
}func re() {content, err := ioutil.ReadFile("./text.txt")if err != nil {fmt.Println(err)return}fmt.Println(string(content))
}
func main() {wr()re()
}
这个工具库相对于其他的工具库更为简单。相应的函数已经被很好的打包完成了。
二、cat命令
package mainimport ("bufio""flag""fmt""io""os"
)// cat 函数接收一个 bufio.Reader 指针作为输入,用于读取文件或标准输入的内容
func cat(r *bufio.Reader) {// 开始一个无限循环,用于逐行读取数据for {// 从 bufio.Reader 中读取一行数据,直到遇到换行符 '\n',存储在 buf 中,并将可能的错误存储在 err 中buf, err := r.ReadBytes('\n')// 如果读取到文件末尾,打印错误信息并退出循环if err == io.EOF {fmt.Println(err)break}// 将读取到的一行数据输出到标准输出fmt.Fprintf(os.Stdout, "%s", buf)}
}func main() {// 解析命令行参数flag.Parse()if flag.NArg() == 0 {// 从标准输入读取数据并输出到标准输出cat(bufio.NewReader(os.Stdin))}// 依次处理每个文件for i := 0; i < flag.NArg(); i++ {// 打开文件f, err := os.Open(flag.Arg(i))if err!= nil {fmt.Fprintf(os.Stderr, "cat: %s: %s\n", flag.Arg(i), err)continue}// 读取文件内容并输出到标准输出cat(bufio.NewReader(f))// 关闭文件f.Close()}
}
上述代码中,cat
函数的主要功能是从 bufio.Reader
中逐行读取数据并输出到标准输出。在 for
循环中,使用 r.ReadBytes('\n')
方法读取一行数据,当遇到文件结束符 io.EOF
时,打印错误信息并退出循环,否则将读取的数据输出到标准输出。在 main
函数中,首先解析命令行参数,若没有命令行参数,则从标准输入读取数据;若有命令行参数,则依次打开文件,调用 cat
函数读取文件内容并输出,最后关闭文件。
注:在 cat
函数中,当遇到 io.EOF
时,打印错误信息可能不是最佳做法,因为 EOF
不是错误,而是文件结束的标志。可以考虑修改为不打印错误信息,仅退出循环。
如果文件中有内容就会打印出文件中的内容。
如果直接执行go run mian.go会打印输出用户输入的内容。
三、包
在 Go 语言中,包(package)是组织代码的一种方式,它可以将相关的函数、变量和类型组合在一起,以便于代码的管理、复用和维护。以下是关于 Go 语言包的一些重要信息:
1. 包的声明
在 Go 文件的开头,使用 package
关键字来声明包的名称。
package main
package main
是一个特殊的包,它表示该文件是一个可执行程序的入口点。- 对于其他包,可以使用其他名称,如
package utils
或package math
。
2. 导入包
使用 import
语句来导入其他包。
import ("fmt""os""github.com/yourusername/yourpackage"
)
- 导入标准库中的包,如
fmt
和os
。 - 导入第三方包,如
github.com/yourusername/yourpackage
。
3. 包的可见性
- 在 Go 中,标识符(函数、变量、类型)的名称首字母大小写决定了其可见性:
- 首字母大写的标识符是导出的,可以被其他包访问。
- 首字母小写的标识符是未导出的,只能在当前包内使用。
package mypackage// 导出的函数
func ExportedFunction() {
}// 未导出的函数
func unexportedFunction() {
}
在另一个包中,可以调用 mypackage.ExportedFunction()
,但不能调用 mypackage.unexportedFunction()
。
4. 包的初始化
包可以包含一个 init
函数,它会在包被导入时自动执行。
package mypackageimport "fmt"func init() {fmt.Println("Initializing mypackage")
}
- 一个包可以有多个
init
函数,它们会按照声明的顺序执行。
5. 标准库包
Go 标准库包含了许多有用的包,例如:
fmt
:格式化输入和输出。os
:提供操作系统功能,如文件操作、环境变量等。io
:提供基本的 I/O 操作接口。bufio
:提供缓冲的 I/O 操作。net
:提供网络编程功能。sync
:提供同步原语,如互斥锁、读写锁等。
6. 第三方包
可以使用 go get
命令来获取第三方包
比如在gin框架学习中引用的gin包
import "github.com/gin-gonic/gin"
7. 包的组织
- 通常,一个目录对应一个包。
- 包的名称应该与目录名称相同,除非使用
package main
。
8. 包的别名
可以为导入的包设置别名。
import (f "fmt"
)
- 这里将
fmt
包的别名设置为f
,可以使用f.Println()
来调用fmt.Println()
。
9. 包的路径
- 包的路径是其在文件系统或远程仓库中的位置。
- 对于标准库,路径是
std
包的一部分,如fmt
包的路径是std/fmt
。 - 对于第三方包,路径是其在远程仓库中的位置,如
github.com/gin-gonic/gin
。
10. 包的版本管理
- Go 1.11 及以后的版本支持模块(module),可以使用
go.mod
文件来管理依赖的版本。 - 例如,创建一个
go.mod
文件:
module mymodulego 1.14require github.com/gin-gonic/gin v1.7.4
这将确保使用 github.com/gin-gonic/gin
的 v1.7.4
版本。
以下是一个完整的示例,展示了包的使用:
package mainimport ("fmt""mypackage"
)func main() {// 使用标准库的 fmt 包fmt.Println("Hello, World!")// 使用自定义包 mypackagemypackage.ExportedFunction()
}
在这个示例中:
- 导入了
fmt
标准库包和mypackage
自定义包。 - 在
main
函数中,调用了fmt.Println()
和mypackage.ExportedFunction()
。
通过合理使用包,可以将代码组织得更加清晰、易于维护和复用,同时利用 Go 语言强大的标准库和丰富的第三方库资源。
四、go mod
go mod
是 Go 语言从 1.11 版本开始引入的模块管理工具,它允许开发者更好地管理项目的依赖关系,而不再依赖于 GOPATH
环境变量。
1. 初始化一个新的模块
使用 go mod init
命令来初始化一个新的模块。例如:
go mod init example.com/myproject
这将创建一个 go.mod
文件,内容如下:
module example.com/myprojectgo 1.14
module
后面的部分是模块的名称,通常是一个唯一的标识符,如域名加项目名。go
后面的部分是 Go 语言的版本。
2. 依赖管理
当你导入一个新的包时,go mod
会自动更新 go.mod
文件。例如:
package mainimport ("github.com/gin-gonic/gin"
)func main() {gin.Default()
}
运行 go build
或 go run
时,go mod
会自动更新 go.mod
文件,添加所需的依赖:
module example.com/myprojectgo 1.14require github.com/gin-gonic/gin v1.7.4
3. 查看依赖关系
使用 go list -m all
命令可以查看所有的依赖关系:
go list -m all
4. 下载依赖
使用 go mod download
命令可以下载所有的依赖:
go mod download
5. 清理未使用的依赖
使用 go mod tidy
命令可以清理未使用的依赖:
go mod tidy
6. 替换依赖
如果需要替换一个依赖,可以在 go.mod
文件中使用 replace
指令。例如:
replace github.com/oldpackage => github.com/newpackage v1.2.3
7. 版本管理
go mod
会自动选择依赖的最新版本,但可以使用require
指令指定版本。例如:
require github.com/gin-gonic/gin v1.7.4
- 可以使用
@
符号指定特定的版本,如v1.7.4
、v1.7.4+incompatible
或v1.7.4-pre
。
8. 私有模块
对于私有模块,可以使用 replace
指令或环境变量 GOPRIVATE
来管理。例如:
replace private.com/myproject => /path/to/local/project
9. 构建和测试
go build
和go test
命令会自动使用go.mod
中的依赖信息。
10. 示例
以下是一个完整的 go.mod
文件示例:
module example.com/myprojectgo 1.14require (github.com/gin-gonic/gin v1.7.4github.com/somepackage v1.2.3
)replace github.com/oldpackage => github.com/newpackage v1.2.3
总结
go mod init
初始化模块。go mod tidy
清理未使用的依赖。go mod download
下载依赖。go mod edit
编辑go.mod
文件。go list -m all
查看依赖。
使用 go mod
可以让 Go 项目的依赖管理更加灵活和方便,避免了 GOPATH
的限制,提高了项目的可维护性和可移植性。
相关文章:
go语言的成神之路-筑基篇-对文件的操作
目录 一、对文件的读写 Reader 接口 Writer接口 copy接口 bufio的使用 ioutil库 二、cat命令 三、包 1. 包的声明 2. 导入包 3. 包的可见性 4. 包的初始化 5. 标准库包 6. 第三方包 7. 包的组织 8. 包的别名 9. 包的路径 10. 包的版本管理 四、go mod 1. 初始…...
两道数据结构编程题
1.写出在顺序存储结构下将线性表逆转的算法,要求使用最少的附加空间。 解:输入:长度为n的线性表数组A(1:n) 输出:逆转后的长度为n的线性表数组A(1:n)。 C语言描述如下(其中ET为数据元素的类型):…...
【Qt】QDateTimeEdit控件实现清空(不保留默认时间/最小时间)
一、QDateTimeEdit控件 QDateTimeEdit 提供了一个用于编辑日期和时间的控件。用户可以通过键盘或使用上下箭头键来增加或减少日期和时间值。日期和时间的显示格式根据设置的格式显示,可以通过 setDisplayFormat() 方法来设置。 二、如何清空 我在使用的时候&#…...
12、字符串
1、字符串概念 字符串用来存储一组字符,因此需要字符数组来存。 C语言中字符串的表示 C语言里面字符串只能用字符数组来存 字符串要求这个数组的末尾必须至少有一个\0 char ch1[] {a,b,c}; // 不是字符串 char ch2[5] {h,e,l,l,o}; // 不是字符串 char…...
DPDK用户态协议栈-Tcp Posix API 1
和udp一样,我们需要实现和系统调用一样的接口来实现我们的tcp server。先来看看我们之前写的unix_tcp使用了哪些接口,这边我加上两个系统调用,分别是接收数据和发送数据。 #include <stdio.h> #include <arpa/inet.h> #include …...
【人工智能-科普】图神经网络(GNN):与传统神经网络的区别与优势
文章目录 图神经网络(GNN):与传统神经网络的区别与优势什么是图神经网络?图的基本概念GNN的工作原理GNN与传统神经网络的不同1. 数据结构的不同2. 信息传递方式的不同3. 模型的可扩展性4. 局部与全局信息的结合GNN的应用领域总结图神经网络(GNN):与传统神经网络的区别与…...
LabVIEW实现UDP通信
目录 1、UDP通信原理 2、硬件环境部署 3、云端环境部署 4、UDP通信函数 5、程序架构 6、前面板设计 7、程序框图设计 8、测试验证 本专栏以LabVIEW为开发平台,讲解物联网通信组网原理与开发方法,覆盖RS232、TCP、MQTT、蓝牙、Wi-Fi、NB-IoT等协议。 结合实际案例,展示如何利…...
[pdf,epub]228页《分析模式》漫谈合集01-45提供下载
《分析模式》漫谈合集01-45的pdf、epub文件提供下载。已上传至本号的CSDN资源。 如果CSDN资源下载有问题,可到umlchina.com/url/ap.html。 已排版成适合手机阅读,pdf的排版更好一些。 ★UMLChina为什么叒要翻译《分析模式》? ★[缝合故事]…...
Kafka的消费消息是如何传递的?
大家好,我是锋哥。今天分享关于【Kafka的消费消息是如何传递的?】面试题。希望对大家有帮助; Kafka的消费消息是如何传递的? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在Kafka中,消息的消费是通过消费…...
二分查找(Java实现)(1)
二分查找(Java实现)(1) leetcode 34.排序数组中查找元素第一个和最后一个位置 题目描述: 给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如…...
力扣103.二叉树的锯齿形层序遍历
题目描述 题目链接103. 二叉树的锯齿形层序遍历 给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。 示例 1ÿ…...
Search with Orama
1.前言 在不久之前,我把 DevNow 的搜索组件通过 Lunr 进行了重构,从前端角度实现了对文章内容的搜索,但是在使用体验上,感觉不是特别好,大概有如下几个原因: 社区的文章数量比较少,项目的 Com…...
一万台服务器用saltstack还是ansible?
一万台服务器用saltstack还是ansible? 选择使用 SaltStack 还是 Ansible 来管理一万台服务器,取决于几个关键因素,如性能、扩展性、易用性、配置管理需求和团队的熟悉度。以下是两者的对比分析,帮助你做出决策: SaltStack&…...
计算机类大厂实习春招秋招开发算法面试问答练习题
计算机类大厂实习春招秋招开发算法面试问答练习题 下面有十个非常重要且常问,面试者却注意不到的问题,我们一个个来看,一个个来学。 线程创建到删除过程中,底层是怎么实现的 1.线程创建 线程创建是线程生命周期的起点。在操作系统中,线程可以通过多种方式创建,但无论哪…...
【热门主题】000068 筑牢网络安全防线:守护数字世界的坚实堡垒
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 【热…...
RPC与HTTP调用模式的架构差异
RPC(Remote Procedure Call,远程过程调用)和 HTTP 调用是两种常见的通信模式,它们在架构上有以下一些主要差异: 协议层面 RPC:通常使用自定义的二进制协议,对数据进行高效的序列化和反序列化&am…...
计算机网络之传输层协议UDP
个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 计算机网络之传输层协议UDP 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记,欢迎大家在评论区交流讨论💌 目…...
Uniapp 微信小程序内打开web网页
技术栈:Uniapp Vue3 简介 实际业务中有时候会需要在本微信小程序内打开web页面,这时候可以封装一个路由页面专门用于此场景。 在路由跳转的时候携带路由参数,拼接上web url,接收页面进行参数接收即可。 实现 webview页面 新…...
阅读方法论
选择固有缺陷,选项是对比出来的...
373. 查找和最小的 K 对数字
参考的这个博客: https://zhuanlan.zhihu.com/p/457239781 然后看这个代码我想到了另外一种方法,就是一步一步往里加元组 ( i , j ) (i,j) (i,j),看代码就知道了,不过需要做一步去重,去重不能用 i n t [ ] int[] int…...
常用函数的使用错题汇总
目录 new/delete malloc/free1. 语言和类型2. 内存分配3. 内存释放4. 安全性和类型安全5. 其他特性总结 线程停止文件流 new/delete malloc/free malloc/free 和 new/delete 是 C/C 中用于动态内存管理的两种方式,它们有一些重要的区别。以下是这两种方式的比较&…...
uniapp手机端一些坑记录
关于 z-paging-x 组件,在ios上有时候通过弹窗去粗发它reload时会触发闪退,可能是弹框插入进去导致的DOM 元素已经被移除或者不可用,解决办法是加上他自带属性 :showRefresherWhenReload"true" 加上showRefresherWhe…...
2024学习之前端微信小程序开发教程,从入门到精通-含基础+实战+源码code
目录 一、简单介绍 二、课程需知 三、内容编排 1、小程序基础 起步式 目录结构 小程序框架 场景值 逻辑层 视图层 组件 视图容器 基础内容 表单组件 导航 媒体组件 Api 路由 界面 交互 网络 数据缓存 自定义组件 2、项目实战 …...
netconf 代码架构
NETCONF(Network Configuration Protocol)是一种基于 XML 的网络配置管理协议,主要用于在网络设备之间进行配置管理、状态监控和操作。它被设计为一种可扩展的协议,并且在自动化网络管理中扮演着重要角色。NETCONF 通过安全的通信…...
蒙特卡洛方法(Monte Carlo,MC)
目录 1 序言 2 Monte Carlo法计算积分 3 最优化计算Monte Carlo法 1 序言 蒙特卡罗方法(Monte Carlo)是由冯诺依曼和乌拉姆等人发明的,“蒙特卡罗”这个名字是出自摩纳哥的蒙特卡罗赌场,这个方法是一类基于概率的方法的统称。是一种应用随机数来进行…...
python学习笔记8-函数2
参数传递 传不可变对象 & 传可变对象 def func(b):print(id(a), a) #140737041872600 234print(id(b), b) #140737041872600 234a 234 func(a)def func(b):print(id(a), a) #1413554098560 [343]print(id(b), b) #1413554098560 [343]a [343] func(a)def func(b):b.appe…...
电商项目高级篇06-缓存
电商项目高级篇06-缓存 1、docker下启动redis2、项目整合redis3、redis改造三级分类业务 缓存 流程图: data cache.load(id);//从缓存加载数据 If(data null){ data db.load(id);//从数据库加载数据 cache.put(id,data);//保存到 cache 中 } return data;在我们…...
使用 `aircrack-ng`扫描、获取握手包
使用 aircrack-ng 工具集来扫描 5GHz WiFi 网络的过程与扫描 2.4GHz 网络类似,但需要注意一些特定的配置和命令。以下是一个详细的步骤指南,帮助你在 5GHz 频段上扫描 WiFi 网络并捕获握手包。 ### 前提条件 1. **操作系统**:通常在 Linux 系…...
基于大数据python 酒店数据分析可视化大屏系统(源码+LW+部署讲解+数据库+ppt)
!!!!!!!!! 很对人不知道选题怎么选 不清楚自己适合做哪块内容 都可以免费来问我 避免后期給自己答辩找麻烦 增加难度(部分学校只有一次答辩机会 没弄好就延迟…...
uniapp中父组件调用子组件方法
实现过程(setup语法糖形式下) 在子组件完成方法逻辑,并封装。在子组件中使用defineExpose暴露子组件的该方法。在父组件完成子组件ref的绑定。通过ref调用子组件暴露的方法。 子组件示例 <template> </template><script se…...
西安企业网站建设公司/网络营销公司如何建立
尽管您可能并不打算完全替代Zimbra来替代电子邮件和协作服务器(请参阅我的前一篇文章 ),但是在像这样的大型开源应用程序中总会藏有很多东西。 Zimbra AJAX工具包(AjaxTK)就是这样的好东西。 对于Zimbra来说࿰…...
杭州网站建设长春公司/杭州网站搜索排名
1.有如下文件,a1.txt,里面的内容为:LNH是最好的培训机构,全心全意为学生服务,只为学生未来,不为牟利。我说的都是真的。哈哈分别完成以下的功能:a,将原文件全部读出来并打印。b,在原文件后面追加…...
个性网站制作/百度搜索引擎推广步骤
我有一个表单验证问题。下面是提交时发生的逻辑(至少是其中的一部分)。在for循环中,我们检查一个站点访问者可以注册的可能事件数组。如果用户没有检查任何事件(这些是复选框,因为用户可以注册多个事件),我们应该在下面输入第二条if语句&…...
怎样选择高性价比的建站公司/sem搜索
import export 这两个家伙对应的就是es6自己的module功能。 我们之前写的Javascript一直都没有模块化的体系,无法将一个庞大的js工程拆分成一个个功能相对独立但相互依赖的小工程,再用一种简单的方法把这些小工程连接在一起。 这有可能导致两个问题&…...
社保网站做员工用工备案/企业网站推广注意事项
选择好的变量名 前注:希望我的读书笔记能带你快速翻过30页的《代码大全》,若有不妥之处,恳请指正。这部分很基础,但也是最常用的,不要小看哦~ http://www.cnblogs.com/jerry19880126/ 对于码农来说,给变量取…...
可以做h5的网站有哪些/网站优化策略分析论文
写在前面 本文一起看下redis作为分布式锁使用的相关内容。 1:怎么算是锁或没锁 锁和没锁本身其实就是用一个变量的值来表示,比如变量lock,当值为1时代表处于上锁状态,当值为0时表示没有锁,那么多线程想要获取锁的话就…...