iOS多线程 - Thread



  • Swift版本: 4.0

    通过 Thread 可以进行多线程编程。

    • 开启新线程
    // 开启一个新线程(方式1)
    Thread.detachNewThread {
        print("New 1 thread: \(Thread.current)")
    }
    
    // 开启一个新线程(方式2)
    Thread.detachNewThreadSelector(#selector(handlePrint), toTarget: self, with: nil)
    再未释放lock情况下
    // 开启一个新线程(方式3)- 直接实例化Thread对象
    let myThread = Thread {
        print("New 3 thread: \(Thread.current)")
    }
    
    myThread.stackSize = 1024 * 16  // 自定义新线程的栈空间大小
    myThread.start()
    

    handlePrint方法定义如下:

    @objc private func handlePrint() {
        print("New 2 thread: \(Thread.current)")
    }
    

    将会输出如下类似日志:(执行顺序是不确定的,下次执行可能就不是该顺序了

    New 2 thread: <NSThread: 0x60c000260180>{number = 3, name = (null)}
    New 3 thread: <NSThread: 0x60c0002602c0>{number = 4, name = (null)}
    New 1 thread: <NSThread: 0x60800006ee00>{number = 5, name = (null)}
    
    • 普通线程锁

    当多个线程需要争夺同一资源的时候,就会用到线程锁。

    自定义Thread类,线程执行的时候将触发 main() 方法。

    // 线程锁
    let lock = NSLock()
    
    class LThread: Thread {
        
        var id: Int = 0
        
        convenience init(id: Int) {
            self.init()
            
            self.id = id
        }
        
        override func main() {
            lock.lock()
            print("\(id) acquired lock")
            lock.unlock()
            if lock.try() {
                print("\(id) acquired lock again")
                lock.unlock()
            } else {
                print("\(id) couldn't acquire lock")
            }
            print("\(id) exit")
        }
        
    }
    

    执行 LThread

    let t1 = LThread(id: 1)
    let t2 = LThread(id: 2)
    t1.start()
    t2.start()
    

    将输出如下类似日志:

    2 acquired lock             // 线程2先获取lock
    2 couldn't acquire lock     // 线程2释放lock后,线程1获取lock,此时线程2再尝试获取lock就失败了
    2 exit                      // 线程2执行结束
    1 acquired lock             // 此时线程1已经获取到了lock
    1 acquired lock again       // unlock释放后,再try,所以线程1重新获取到了lock
    1 exit                      // 然后线程1释放lock,并执行结束
    
    • 递归锁

    如果一个线程多次请求获取lock,可能会导致线程阻塞,因为第一次获取到了lock后,在未释放lock情况下,再次申请获取lock,将会获取失败,这里就需要用到递归锁了。

    创建递归锁NSRecursiveLock以及RThread

    // 递归锁
    let rLock = NSRecursiveLock()
    
    class RThread: Thread {
        
        override func main() {
            rLock.lock()
            print("Thread main acquired lock")
            callMe()
            rLock.unlock()
            print("RThread main exit")
        }
        
        private func callMe() {
            rLock.lock()
            print("Thread callMe acquired lock")
            rLock.unlock()
            print("RThread callMe exit")
        }
        
    }
    

    执行该线程

    let thread = RThread()
    thread.start()
    

    将输出如下日志:

    Thread main acquired lock
    Thread callMe acquired lock
    RThread callMe exit
    RThread main exit
    

    如果不是递归锁的话,该线程将会被阻塞。

    • 条件锁

    条件锁是当满足特定条件的情况下,才能获取到lock。

    定义 ProducerThreadConsumerThread ,以及条件锁。

    let NO_DATA = 1
    let GOT_DATA = 2
    let conditionLock = NSConditionLock(condition: NO_DATA)
    var sharedInt = 0
    
    class ProducerThread: Thread {
        
        override func main() {
            for i in 0..<5 {
                // 当条件为 NO_DATA 时,获取锁
                // 如果不想等待消费者,可以通过 conditionLock.lock() 直接获取锁
                conditionLock.lock(whenCondition: NO_DATA)
                
                print("ProducerThread main acquired lock")
                
                sharedInt = i
                
                print("ProducerThread main sharedInt = \(sharedInt)")
                
                // 解锁并设置条件为 GOT_DATA
                conditionLock.unlock(withCondition: GOT_DATA)
            }
        }
        
    }
    
    class ConsumerThread: Thread {
        
        override func main() {
            for i in 0..<5 {
                // 当条件为 GOT_DATA 时,获取锁
                conditionLock.lock(whenCondition: GOT_DATA)
                
                print("ConsumerThread main acquired lock")
                
                sharedInt = i
                
                print("ConsumerThread main sharedInt = \(sharedInt)")
                
                // 解锁并设置条件为 NO_DATA
                conditionLock.unlock(withCondition: NO_DATA)
            }
        }
        
    }
    

    执行该线程

    let producerThread = ProducerThread()
    let consumerThread = ConsumerThread()
    producerThread.start()
    consumerThread.start()
    

    将输出如下日志:

    ProducerThread main acquired lock
    ProducerThread main sharedInt = 0
    ConsumerThread main acquired lock
    ConsumerThread main sharedInt = 0
    ProducerThread main acquired lock
    ProducerThread main sharedInt = 1
    ConsumerThread main acquired lock
    ConsumerThread main sharedInt = 1
    ProducerThread main acquired lock
    ProducerThread main sharedInt = 2
    ConsumerThread main acquired lock
    ConsumerThread main sharedInt = 2
    ProducerThread main acquired lock
    ProducerThread main sharedInt = 3
    ConsumerThread main acquired lock
    ConsumerThread main sharedInt = 3
    ProducerThread main acquired lock
    ProducerThread main sharedInt = 4
    ConsumerThread main acquired lock
    ConsumerThread main sharedInt = 4
    

    条件锁初始条件为 NO_DATA ,如果 ConsumerThread 先尝试获取lock的话,因不满足条件,将会被阻塞。只有 ProducerThread 满足 NO_DATA 条件,将优先会获取到lock。ProducerThread 释放lock后将条件锁的条件设置为 GOT_DATA ,进而 ConsumerThread 将会有能力获取到lock,ProducerThreadConsumerThread 相互交替执行,直至结束。

    • 条件(NSCondition)

    如果在已获取lock的情况下想等待某些操作结束后继续执行的话,就用到了 NSCondition 。 NSCondition 与 NSConditionLock 不一样,NSCondition 提供了更加清晰的等待条件产生的方式。

    定义 WriterThreadPrinterThread ,以及 NSCondition

    let condition = NSCondition()
    var available = false
    var sharedString = ""
    
    class WriterThread: Thread {
        
        override func main() {
            for i in 0..<5 {
                condition.lock()
                
                sharedString = "zzb_\(i)"
                available = true
                
                condition.signal()  // 通知并且唤醒等待的线程
                
                condition.unlock()
            }
        }
        
    }
    
    class PrinterThread: Thread {
        
        override func main() {
            for _ in 0..<5 {
                condition.lock()
                
                while(!available) {
                    condition.wait()
                }
                print("PrinterThread main sharedString = \(sharedString)")
                sharedString = ""
                available = false
                
                condition.unlock()
            }
        }
        
    }
    

    执行该线程

    let writerThread = WriterThread()
    let printerThread = PrinterThread()
    writerThread.start()
    printerThread.start()
    

    将输出如下日志:

    PrinterThread main sharedString = zzb_0
    PrinterThread main sharedString = zzb_1
    PrinterThread main sharedString = zzb_2
    PrinterThread main sharedString = zzb_3
    PrinterThread main sharedString = zzb_4
    

Log in to reply