固定时长定时器
- 写法一
package main
import (
"fmt"
"time"
)
func main() {
//创建3秒定时器
timer := time.NewTimer(3*time.Second)
fmt.Println("定时器创建完毕")
//打印当前时间
fmt.Println(time.Now())
x := <-timer.C
fmt.Println(x)
}
2) 写法二
package main
import (
"fmt"
"time"
)
func main() {
//打印当前时间
fmt.Println(time.Now())
x := <-time.After(3*time.Second)
fmt.Println("定时器创建完毕")
}
周期性长定时器
package main
import (
"fmt"
"time"
)
func main() {
//创建一个1秒为周期的秒表
ticker := time.NewTicker(1 * time.Second)
var i int
for {
//每隔1秒读出当前时间
x := <-ticker.C
fmt.Print("\n", x)
//10秒后停止计时并退出
i++
if i > 9 {
ticker.Stop()
break
}
}
fmt.Println("计时结束")
}
定时器的终止和重置
package main
import (
"time"
"fmt"
)
func main() {
timer := time.NewTimer(3 * time.Second)
fmt.Println(time.Now(), "炸弹将于3秒后引爆")
//趁定时器未到时间,将定时器终止
timer.Stop()
fmt.Println("炸弹已被拆除,定时器失效")
//定时器已被叫停,其时间管道永远读不出数据了--死锁
//fatal error: all goroutines are asleep - deadlock!
t := <-timer.C
fmt.Println("炸弹引爆于", t)
}
等待组
package main
import (
"fmt"
"sync"
"time"
)
func main041() {
//创建任务等待组
var wg sync.WaitGroup
//向等待组中添加任务
wg.Add(1)
wg.Add(1)
wg.Add(1)
//从等待组中抹掉任务
wg.Done()
wg.Done()
wg.Done()
//阻塞等待至等待组中的任务数为0
wg.Wait()
}
func main() {
var wg sync.WaitGroup
wg.Add(1)
go func() {
for i := 0; i < 5; i++ {
fmt.Println("子协程1", i)
<-time.After(1 * time.Second)
}
fmt.Println("子协程1结束任务")
wg.Done()
}()
wg.Add(1)
go func() {
var i int
ticker := time.NewTicker(1 * time.Second)
for {
<-ticker.C
i++
fmt.Println("子协程2", "秒表:", i)
if i > 9 {
break
}
}
fmt.Println("子协程2结束任务")
wg.Done()
}()
//等待组阻塞等待至记录清零为止
wg.Wait()
fmt.Println("END")
}
互斥锁
1)并发安全问题,每次累加数据都不一样
package main
import (
"fmt"
"sync"
)
func main() {
//创建任务等待组
var wg sync.WaitGroup
var money = 2000
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
//并发安全问题,每次累加数据都不一样
for j := 0; j < 10000; j++ {
money += 1
}
wg.Done()
}()
}
//阻塞等待至等待组中的任务数为0
wg.Wait()
fmt.Println("最终金额", money)
}
2)加互斥锁
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func main() {
var money = 2000
//一支麦克
var mt sync.Mutex
wg.Add(1)
go func() {
fmt.Println("鹤姐开始抢麦")
//谁抢到麦谁才有资格修改money,其他抢麦的协程就必须阻塞等待
mt.Lock()
fmt.Println("鹤姐抢到了麦,何洁开始嗨")
money -= 300
<-time.After(10*time.Second)
//曲罢弃麦,其它人再去哄抢
mt.Unlock()
fmt.Println("鹤姐弃麦")
wg.Done()
}()
wg.Add(1)
go func() {
fmt.Println("鹤哥开始抢麦")
//谁抢到麦谁才有资格修改money,其他抢麦的协程就必须阻塞等待
mt.Lock()
fmt.Println("鹤哥抢到了麦,鹤哥开始嗨")
money -= 500
<-time.After(10*time.Second)
//曲罢弃麦,其它人再去哄抢
mt.Unlock()
fmt.Println("鹤哥弃麦")
wg.Done()
}()
/*不抢麦的人不会被阻塞*/
wg.Add(1)
go func() {
fmt.Println("abcdefg")
<-time.After(1*time.Second)
fmt.Println("hijklmn")
<-time.After(1*time.Second)
fmt.Println("opqrst")
<-time.After(1*time.Second)
fmt.Println("uvwxyz")
wg.Done()
}()
wg.Wait()
}
信号量控制最大并发数
控制最大并发数量
package main
import (
"fmt"
"math"
"sync"
"time"
)
var wg08 sync.WaitGroup
var chSem chan int
func main() {
//semaphore信号量
chSem = make(chan int, 5)
for i := 0; i < 100; i++ {
wg08.Add(1)
go getSqrt(i)
}
wg08.Wait()
}
func getSqrt(n int) {
//规定:所有并发任务都必须注册在信号量管道里
chSem <- n
fmt.Printf("%d的平方根是%.2f\n", n, math.Sqrt(float64(n)))
<- time.After(10 * time.Second)
//任务结束后从信号量管道注销,给其它腾出空间
<-chSem
wg08.Done()
}
死锁现象
1)自己阻塞自己
package main
import "fmt"
//自己阻塞自己
func main() {
ch := make(chan int, 0)
ch <- 123
x := <-ch
fmt.Println(x)
}
2)开塞露协程-开晚了
package main
import "fmt"
//开塞露协程-开晚了
func main() {
ch := make(chan int, 0)
ch <- 123
go func() {
x := <-ch
fmt.Println(x)
}()
}
3)管道读写时,相互要求对方先读/写,自己在写/读,造成死锁
package main
import (
"fmt"
)
/*读写锁定相互阻塞,形成隐形死锁*/
func main() {
chHusband := make(chan int, 0)
chWife := make(chan int, 0)
//老公
go func() {
for{
select {
//只要我有钱我就给你发红包
case <- chHusband:
chWife <- 123
fmt.Println("老公:我已经给你发123元红包了")
case chWife <- 1:
fmt.Println("老公:我已经给你发1元红包了")
}
}
}()
//老婆
select {
//只要我有钱我就给你发红包
case <- chWife:
chHusband <- 123
fmt.Println("老婆:我已经给你发123元红包了")
}
fmt.Println("THE END")
}
4)读写锁定相互阻塞,形成隐形死锁
package main
import (
"fmt"
"runtime"
"sync"
)
/*读写锁定相互阻塞,形成隐形死锁*/
func main() {
var rwm09 sync.RWMutex
ch := make(chan int, 0)
//子协程负责写入
go func() {
//连锁都抢不到555...
rwm09.Lock()
ch <- 123
rwm09.Unlock()
}()
go func() {
//本协程负责读出
rwm09.RLock()
//只要读不到内容就永远阻塞
x := <-ch
fmt.Println("读到", x)
rwm09.RUnlock()
}()
for {
//通知垃圾回收器来清理垃圾(即使不叫也会定时清理)
runtime.GC()
}
}