import "sync"
// 顺序队列
type SequentialQueue[T interface{}] struct {
item []T
lock sync.Mutex //加锁以便多线程使用
}
// 创建一个顺序队列
func NewSQueue[T interface{}]() *SequentialQueue[T] {
return &SequentialQueue[T]{}
}
// 入队
func (s *SequentialQueue[T]) Put(value T) {
s.lock.Lock()
s.item = append(s.item, value)
s.lock.Unlock()
}
// 出队
func (s *SequentialQueue[T]) Pop() (T, bool) {
s.lock.Lock()
var value T
if s.IsEmpty() {
return value, false
}
value = s.item[0]
s.item = s.item[1:]
s.lock.Unlock()
return value, true
}
// 顺序队列的长度
func (s *SequentialQueue[T]) Len() int {
return len(s.item)
}
// 判断队列是否为空
func (s *SequentialQueue[T]) IsEmpty() bool {
return s.Len() == 0
}
这里我使用了空接口作为泛型类型,在go1.18之后空接口的定义是所有类型的集合,所以这个队列可以存放任意类型的数据。同时我对出队与入队加了锁,所以此队列在多线程环境下是线程安全的。使用注意需要go1.18以上版本。
测试:
单线程
func TestPut(t *testing.T) {
squeue := queue.NewSQueue[string]()
for i := 0; i < 10; i++ {
squeue.Put(fmt.Sprint(i))
}
fmt.Println("队列长度:", squeue.Len())
for {
value, bl := squeue.Pop()
if !bl {
break
}
fmt.Print(value + " ")
}
fmt.Println()
fmt.Println("队列运行结束,队列的长度是:", squeue.Len(), squeue.IsEmpty())
}
结果:
多线程
func TestThreadSqunen(t *testing.T) {
squeue := queue.NewSQueue[string]()
for i := 0; i < 20; i++ {
squeue.Put(fmt.Sprint(i))
}
go printSqueue[string](squeue)
go printSqueue[string](squeue)
time.Sleep(5 * time.Second)
fmt.Println()
fmt.Println("队列运行结束,队列的长度是:", squeue.Len(), squeue.IsEmpty())
}
func printSqueue[T interface{}](s *queue.SequentialQueue[T]) {
for {
value, bl := s.Pop()
if !bl {
break
}
fmt.Print(fmt.Sprintf("%v ", value))
}
}
结果:
可以看到多线程情况下队列是线程安全的。