github.com/rolandhe/saber@v0.0.4/gocc/defaultBlockingqueue.go (about) 1 // Golang concurrent tools like java juc. 2 // 3 // Copyright 2023 The saber Authors. All rights reserved. 4 // 5 6 package gocc 7 8 import ( 9 "time" 10 ) 11 12 const defaultLimit = 128 13 14 // NewDefaultBlockingQueue 构建一个有界队列,缺省的队列底层使用channel 15 // 16 // limit 队列容量 17 func NewDefaultBlockingQueue[T any](limit int64) BlockingQueue[T] { 18 if limit < 0 { 19 limit = defaultLimit 20 } 21 return &chanBlockingQueue[T]{ 22 make(chan *Elem[T], limit), 23 } 24 } 25 26 // Elem 进入队列的元素使用Elem来封装 27 type Elem[T any] struct { 28 v *T 29 } 30 31 // GetValue 获取Elem内封装的数据 32 func (el *Elem[T]) GetValue() T { 33 return *(el.v) 34 } 35 36 // BlockingQueue 线程安全地有界队列, 支持阻塞offer/pull, 超时offer/pull,立即offer/pull 37 type BlockingQueue[T any] interface { 38 // Offer 写入队列,如果队列已满,等待,直到写入位置 39 Offer(t T) 40 // TryOffer 尝试写入队列,如果当前队列已满,立即返回false,如果能够写入,返回true 41 TryOffer(t T) bool 42 // OfferTimeout 超时写入,等待时间内写入返回true,否则返回false 43 OfferTimeout(t T, timeout time.Duration) bool 44 // Pull 与Offer相反, 从队列读取数据,如果队列为空,阻塞,直至有数据位置 45 Pull() *Elem[T] 46 // TryPull 尝试读取数据,如果队列有数据直接返回,如果队列为空,返回false 47 TryPull() (*Elem[T], bool) 48 // PullTimeout 超时读取,等待时间内读取到数据返回true,否则返回false 49 PullTimeout(timeout time.Duration) (*Elem[T], bool) 50 } 51 52 // 基于golang channel实现,构建buffered channel,利用channel的并发安全能力来实现并发队列, 53 // channel是不能被close的,所以应用是推荐使用TryOffer/TryPull和超时方法 54 type chanBlockingQueue[T any] struct { 55 q chan *Elem[T] 56 } 57 58 func (ci *chanBlockingQueue[T]) Offer(t T) { 59 ci.q <- &Elem[T]{&t} 60 } 61 62 func (ci *chanBlockingQueue[T]) TryOffer(t T) bool { 63 select { 64 case ci.q <- &Elem[T]{&t}: 65 return true 66 default: 67 return false 68 } 69 } 70 71 func (ci *chanBlockingQueue[T]) OfferTimeout(t T, timeout time.Duration) bool { 72 select { 73 case ci.q <- &Elem[T]{&t}: 74 return true 75 case <-time.After(timeout): 76 return false 77 } 78 } 79 80 func (ci *chanBlockingQueue[T]) Pull() *Elem[T] { 81 v := <-ci.q 82 return v 83 } 84 85 func (ci *chanBlockingQueue[T]) TryPull() (*Elem[T], bool) { 86 select { 87 case v := <-ci.q: 88 return v, true 89 default: 90 return nil, false 91 } 92 } 93 func (ci *chanBlockingQueue[T]) PullTimeout(timeout time.Duration) (*Elem[T], bool) { 94 select { 95 case v := <-ci.q: 96 return v, true 97 case <-time.After(timeout): 98 return nil, false 99 } 100 }