线程之5-多线程经典题目

多线程经典题目,如何让两个线程交替输出?
就像这样:

{number = 6, name = (null)}thred acion doing log with flag 1
{number = 7, name = (null)}thred acion doing log with flag 2
{number = 6, name = (null)}thred acion doing log with flag 1
{number = 7, name = (null)}thred acion doing log with flag 2

如果想要实现这样的效果,那么线程是不能被释放的,因为线程一旦释放,再次异步执行的时候就会创建新线程,不符合题目要求,所以结合线程保活,只能用runLoop 来实现。
先看下 RunLoop 都有哪些启动方法:

//Puts the receiver into a permanent loop, during which time it processes data from all attached input sources.
open func run()

//Runs the loop until the specified date, during which time it processes data from all attached input sources.
open func run(until limitDate: Date)

//Runs the loop once, blocking for input in the specified mode until a given date.
open func run(mode: RunLoop.Mode, before limitDate: Date) -> Bool

//Runs the loop once or until the specified date, accepting input only for the specified mode.
open func acceptInput(forMode mode: RunLoop.Mode, before limitDate: Date)

这三种方式无论通过哪一种方式启动runloop,如果没有一个输入源或者timer附加于runloop上,runloop就会立刻退出。

(1) 第一种方式,runloop会一直运行下去,在此期间会处理来自输入源的数据,并且会在NSDefaultRunLoopMode模式下重复调用runMode:beforeDate:方法;

(2)第二种方式,runloop会在指定时间之前一直运行,在此期间会处理来自输入源的数据,并且会在NSDefaultRunLoopMode模式下重复调用runMode:beforeDate:方法;

(3) 第三种方式,可以设置超时时间,在超时时间到达之前,runloop会一直运行,在此期间runloop会处理来自输入源的数据,并且也会在NSDefaultRunLoopMode模式下重复调用runMode:beforeDate:方法;

(4) 第四种方式,runloop会运行一次,超时时间到达或者第一个input source被处理,则runloop就会退出。

退出Runloop 的方式

与开启runloop 的方式对应

  • 如果想退出runloop,不应该使用第一种启动方式来启动runloop。
    如果runloop没有input sources或者附加的timer,runloop就会退出。
    虽然这样可以将runloop退出,但是苹果并不建议我们这么做,因为系统内部有可能会在当前线程的runloop中添加一些输入源,所以通过手动移除input source或者timer这种方式,并不能保证runloop一定会退出。
  • 第二种和第三种方式可以通过设置超时时间来退出runloop。

手动退出runloop

@objc func endAllSubRunLoop() {
        debugPrint("\(Thread.current) end!!!")
        CFRunLoopStop(CFRunLoopGetCurrent())
    }

如何实现两个线程交替输出

self.thread1 = Thread(target: self, selector: #selector(startSubThread), object: nil)
self.thread1.start()
        
self.thread2 = Thread(target: self, selector: #selector(startSubThread), object: nil)
self.thread2.start()
@objc func startSubThread() {
      let runLoop = RunLoop.current
      runLoop.add(Port(), forMode: .default)
      runLoop.run(until: .distantFuture)
      debugPrint("runLoop 启动 at: \(Thread.current)")
  }

@IBAction func beginCrossAction(_ sender: Any) {
    self.endRunLoop = false
    self.perform(#selector(subThread1Action), on: self.thread1, with: nil, waitUntilDone: false)
  }

@IBAction func endCrossAction(_ sender: Any) {
        self.endRunLoop = true
}

@objc func endAllSubRunLoop() {
        debugPrint("\(Thread.current) end!!!")
        CFRunLoopStop(CFRunLoopGetCurrent())
    }
@objc func subThread1Action() {
        if endRunLoop {
            self.endAllSubRunLoop()
        } else {
            print("\(Thread.current)thred acion doing log with flag 1")
            self.perform(#selector(subThread2Action), on: self.thread2, with: nil, waitUntilDone: false)
        }
    }
    
    @objc func subThread2Action() {
        if endRunLoop {
            self.endAllSubRunLoop()
        } else {
            print("\(Thread.current)thred acion doing log with flag 2")
            self.perform(#selector(subThread1Action), on: self.thread1, with: nil, waitUntilDone: false)
        }
    }

输出如下

{number = 6, name = (null)}thred acion doing log with flag 1
{number = 7, name = (null)}thred acion doing log with flag 2
{number = 6, name = (null)}thred acion doing log with flag 1
{number = 7, name = (null)}thred acion doing log with flag 2
{number = 6, name = (null)}thred acion doing log with flag 1
{number = 7, name = (null)}thred acion doing log with flag 2
{number = 6, name = (null)}thred acion doing log with flag 1
{number = 7, name = (null)}thred acion doing log with flag 2
{number = 6, name = (null)}thred acion doing log with flag 1
{number = 7, name = (null)}thred acion doing log with flag 2
{number = 6, name = (null)}thred acion doing log with flag 1
{number = 7, name = (null)}thred acion doing log with flag 2
{number = 6, name = (null)}thred acion doing log with flag 1
{number = 7, name = (null)}thred acion doing log with flag 2

你可能感兴趣的:(线程之5-多线程经典题目)