本篇内容多线程相关
一.锁的分类
种类:
NSLock,NSConditionLock,NSRecursiveLock, NSCondition.
对比
- 都遵循NSLocking协议.
public protocol NSLocking {
func lock()
func unlock()
}
- 除了NSCondition,其它三种锁都是有以下两个方法
func `try`() -> Bool
func lock(before limit: Date) -> Bool
二.锁的定义,使用及注意点**
1.NSLock
定义
在同一应用程序中协调多个执行线程的操作的对象。
使用
NSLock对象可以用来作为对应用程序全局数据的中间访问,或者用来保护代码的关键部分,允许它自动运行。
注意点
- 加锁解锁必须在同一线程.
- 不应该使用这个类来实现递归锁。在同一个线程上调用两次锁方法将会永久锁定线程。
- 解锁未锁定的锁被认为是程序员的错误,应该在代码中修复。当错误发生时,NSLock类通过向控制台打印错误消息来报告这些错误。
测试
- 1.基本使用,锁住关键代码.
- 2.tryLock方法尝试获取锁,但如果锁不可用,则不会阻塞;相反,该方法只返回NO.
- 3.lockBeforeDate方法尝试获取锁,但是如果在指定的时间限制内没有获取锁,则解除线程阻塞(并返回NO)。
代码测试:
1.的测试
//在多线程中调用测试:
func saleTickets() {
//加锁
lock.lock()
sleep(2)
if ticket > 0{
ticket -= 1
print(Date(),"当前票数\(ticket)")
}else{
print("没有票了")
//解锁
lock.unlock()
return
}
//解锁
lock.unlock()
}
2.的测试
func testTryLock(){
let lock = NSLock()
DispatchQueue.global().async {
lock.lock()
print(Date(),"线程1执行")
sleep(2)
lock.unlock()
print(Date(),"线程1解锁")
}
DispatchQueue.global().async {
sleep(1)
if lock.try(){
print(Date(),"线程2执行")
}else{
print(Date(),"线程2加锁失败")
}
}
}
打印结果:
2019-10-31 09:50:09 +0000 线程1执行
2019-10-31 09:50:10 +0000 线程2加锁失败
2019-10-31 09:50:11 +0000 线程1解锁
3.的测试
func testLockBefor(){
let lock = NSLock()
DispatchQueue.global().async {
lock.lock()
print(Date(),"线程1执行")
//分别测试2,8,观察结果.
sleep(2)
lock.unlock()
print(Date(),"线程1解锁")
}
DispatchQueue.global().async {
sleep(1)
if lock.lock(before: Date.init(timeIntervalSinceNow: 4)){
print(Date(),"线程2执行")
}else{
print(Date(),"线程2加锁失败")
}
}
}
2.NSConditionLock
定义
可以与特定的用户定义条件相关联的锁。
使用
使用NSConditionLock对象,您可以确保只有在满足特定条件时,线程才能获得锁。一旦获得了锁并执行了代码的关键部分,线程就可以放弃锁并将相关条件设置为新的内容。这些条件本身是任意的:您可以根据应用程序的需要来定义它们。
测试
//代码如下:
func testNSConditionLock(){
let lock = NSConditionLock.init(condition: 0)
DispatchQueue.global().async {
if lock.tryLock(whenCondition: 0){
print(Date(),"线程1执行")
sleep(1)
lock.unlock(withCondition: 1)
}else{
print("线程1枷锁失败")
}
}
DispatchQueue.global().async {
lock.lock(whenCondition: 3)
print(Date(),"线程2执行")
sleep(1)
lock.unlock(withCondition: 2)
}
DispatchQueue.global().async {
lock.lock(whenCondition: 1)
print(Date(),"线程3执行")
sleep(1)
lock.unlock(withCondition: 3)
}
}
3.NSRecursiveLock
定义
同一线程可以多次获得而不会导致死锁的锁。
使用
NSRecursiveLock定义了一个锁,它可以被同一个线程多次获得而不会导致死锁,这种情况下,一个线程被永久阻塞,等待它自己放弃一个锁。虽然锁定线程有一个或多个锁,但所有其他线程都不能访问该锁保护的代码。
测试
func testRecursiveLock(){
printPattern(n: 10)
}
func printPattern(n : Int) {
//nsLock.lock()//NSLock死锁
recursiveLock.lock()
if n <= 0 {
print(n)
}
else {
print(n)
printPattern(n: n - 5)
print(n)
}
//nsLock.unlock()
recursiveLock.unlock()
}
4.NSCondition
定义
A condition variable whose semantics follow those used for POSIX-style conditions.
使用
条件对象同时充当给定线程中的锁和检查点。锁在测试条件并执行条件触发的任务时保护代码。检查点行为要求在线程执行其任务之前条件为true。当条件不为真时,线程阻塞。它保持阻塞状态,直到另一个线程发出条件对象的信号。
测试
1.锁住关键代码,通过条件控制线程的进行.
let nsCondition = NSCondition()
//
var products: [NSObject] = []
DispatchQueue.global().async {
while(true){
nsCondition.lock()
if products.count == 0{
print(Date(),"消费1缺货等待")
nsCondition.wait()
}
print(Date(),"消费1执行")
products.removeFirst()
nsCondition.unlock()
}
}
DispatchQueue.global().async {
while(true){
nsCondition.lock()
print(Date(),"生产线程执行")
products.append(NSObject())
nsCondition.signal()
nsCondition.unlock()
sleep(1)
}
}
2.唤醒其它一个或多个线程
let nsCondition = NSCondition()
DispatchQueue.global().async {
nsCondition.lock()
print("线程1加锁成功", Thread.current)
nsCondition.wait()
print("线程1")
nsCondition.unlock()
print("线程1解锁成功", Thread.current)
}
DispatchQueue.global().async {
nsCondition.lock()
print("线程2加锁成功", Thread.current)
nsCondition.wait()
print("线程2")
nsCondition.unlock()
print("线程2解锁成功", Thread.current)
}
DispatchQueue.global().async {
sleep(2)
//唤醒一个等待的线程
// print("唤醒一个等待的线程")
// nsCondition.signal()
//唤醒所有等待的线程
print("唤醒所有等待的线程")
nsCondition.broadcast()
}