feat(完整功能): 以Apache License 2.0协议开源

This commit is contained in:
2025-09-24 02:58:49 +08:00
parent 1a53a5ab8f
commit 0d90c09d71
5 changed files with 951 additions and 1 deletions

142
example_test.go Normal file
View File

@@ -0,0 +1,142 @@
// Copyright 2025 肖其顿
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package klock_test
import (
"fmt"
"sync"
"time"
"github.com/xiaoqidun/klock"
)
// ExampleKeyLock_Lock 演示了如何使用 Lock 和 Unlock 来保护对共享资源的并发写操作。
func ExampleKeyLock_Lock() {
kl := klock.New()
var wg sync.WaitGroup
// 共享数据
sharedData := make(map[string]int)
// 模拟10个并发请求更新同一个键的值
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
// 为 "dataKey" 加锁,确保同一时间只有一个 goroutine 能修改其值
kl.Lock("dataKey")
sharedData["dataKey"]++
kl.Unlock("dataKey")
}()
}
wg.Wait()
fmt.Printf("键 'dataKey' 的最终计数值是: %d\n", sharedData["dataKey"])
// Output: 键 'dataKey' 的最终计数值是: 10
}
// ExampleKeyLock_RLock 演示了多个 goroutine 如何同时获取读锁以并发地读取数据。
func ExampleKeyLock_RLock() {
kl := klock.New()
sharedResource := "这是一个共享资源"
// 启动5个 goroutine 并发读取数据
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(gid int) {
defer wg.Done()
kl.RLock("resourceKey")
fmt.Printf("Goroutine %d 读取资源: %s\n", gid, sharedResource)
kl.RUnlock("resourceKey")
}(i)
}
wg.Wait()
// 注意:由于 goroutine 调度顺序不确定,输出的顺序可能不同。
// 但这个示例的核心是展示它们可以并发执行,而不会像写锁一样互相等待。
}
// ExampleKeyLock_TryLock 演示了如何尝试非阻塞地获取锁。
// 如果锁已被占用,它不会等待,而是立即返回 false。
func ExampleKeyLock_TryLock() {
kl := klock.New()
key := "resource_key"
// 第一次尝试,应该成功
if kl.TryLock(key) {
fmt.Println("第一次 TryLock 成功获取锁")
// 第二次尝试,因为锁已被持有,所以应该失败
if !kl.TryLock(key) {
fmt.Println("第二次 TryLock 失败,因为锁已被占用")
}
kl.Unlock(key)
}
// Output:
// 第一次 TryLock 成功获取锁
// 第二次 TryLock 失败,因为锁已被占用
}
// ExampleKeyLock_LockWithTimeout 演示了如何在指定时间内尝试获取锁,避免无限期等待。
func ExampleKeyLock_LockWithTimeout() {
kl := klock.New()
key := "task_key"
// 主 goroutine 先获取锁
kl.Lock(key)
fmt.Println("主 goroutine 持有锁")
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
// 尝试在 10ms 内获取锁,此时主 goroutine 仍持有锁,所以会失败
fmt.Println("Goroutine 尝试在 10ms 内获取锁...")
if !kl.LockWithTimeout(key, 10*time.Millisecond) {
fmt.Println("Goroutine 获取锁超时,任务取消")
}
}()
// 等待 20ms 后释放锁
time.Sleep(20 * time.Millisecond)
kl.Unlock(key)
fmt.Println("主 goroutine 释放锁")
wg.Wait()
// Output:
// 主 goroutine 持有锁
// Goroutine 尝试在 10ms 内获取锁...
// Goroutine 获取锁超时,任务取消
// 主 goroutine 释放锁
}
// ExampleKeyLock_Status 演示了如何查询一个键的当前锁定状态。
func ExampleKeyLock_Status() {
kl := klock.New()
key := "status_key"
var wg sync.WaitGroup
kl.Lock(key)
// 启动两个 goroutine 在后台等待锁
for i := 0; i < 2; i++ {
wg.Add(1)
go func() {
defer wg.Done()
kl.Lock(key)
time.Sleep(1 * time.Millisecond)
kl.Unlock(key)
}()
}
// 等待一小段时间,确保两个 goroutine 已经处于等待状态
time.Sleep(10 * time.Millisecond)
holders, waiters := kl.Status(key)
fmt.Printf("当前持有者: %d, 等待者: %d\n", holders, waiters)
kl.Unlock(key)
wg.Wait()
holders, waiters = kl.Status(key)
fmt.Printf("所有任务完成后,持有者: %d, 等待者: %d\n", holders, waiters)
// Output:
// 当前持有者: 1, 等待者: 2
// 所有任务完成后,持有者: 0, 等待者: 0
}