iOS-机制

iOS-多线程(一)原理

2020-02-29  本文已影响0人  xxxxxxxx_123

基本概念

线程

线程是进程的基本执行单元,一个进程的所有任务都在线程中执行 进程要想执行任务,必须得有线程,进程至少要有一条线程。
程序启动会默认开启一条线程,这条线程被称为主线程或UI线程。

进程

进程是指在系统中正在运行的一个应用程序。每个进程之间是独立的,每个进程均运行在其专用的且受保护的内存。

线程与进程的关系

例如,有一个进程是打扫教室,其中扫地、擦桌子、擦玻璃、擦黑板就是不同的线程。

多线程原理

CPU在单位时间片里在各个线程之间切换。

线程的生命周期包含5个阶段,包括:新建、准备、运行、阻塞、销毁。

整个流程如下所示:

image

多线程处理是通过线程池来进行的,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池中的线程都是后台线程。每个线程都有默认的堆栈大小,以默认的优先级运行,并处在多线程单元中。线程池的

image

饱和策略分为四种,均实现的RejectedExecutionHandler接口:

多线程的优缺点

优点:

缺点:

iOS多线程技术

iOS多线程有很多技术,下面做了一下对比:

image

对比得知,我们一般主要使用的还是GCDNSOperation

线程和runloop的关系

线程间的通讯

多线程之间的通讯,除过简单的获取主线程,还有2种方式。

  1. performSelector:onThread。比如说有AB两个线程,我们可以在A线程里使用该方法,调用B的方法,然后再在B线程里使用该方法调用A线程的方法,这样就实现了线程之间的通讯。
- (void)performSelectorOnMainThread:(SEL)aSelector      
                         withObject:(nullable id)arg
                         waitUntilDone:(BOOL)wait

- (void)performSelector:(SEL)aSelector 
               onThread:(NSThread *)thr 
               withObject:(nullable id)arg waitUntilDone:(BOOL)wait
  1. NSPortNSPort使用的方式为接收线程中注册NSPort,在另外的线程中使用此port发送消息,则被注册线程会收到相应消息,然后最终在主线程里调用某个回调函数。

NSPort有3个子类,NSSocketPortNSMessagePortNSMachPort,但在iOS下只有NSMachPort可用。

NSMachPort的方式如下:

@property (nonatomic, strong) NSPort *aPort;
@property (nonatomic, strong) TPerson *person;

//1. 创建主线程的port
// 子线程通过此端口发送消息给主线程
self.aPort = [NSMachPort port];
//2. 设置port的代理回调对象
self.aPort.delegate = self;
//3. 把port加入runloop,接收port消息
[[NSRunLoop currentRunLoop] addPort:self.aPort forMode:NSDefaultRunLoopMode];
    
self.person = [[TPerson alloc] init];
[NSThread detachNewThreadSelector:@selector(personLaunchThreadWithPort:) toTarget:self.person withObject:self.aPort];
@interface TPerson : NSObject
- (void)personLaunchThreadWithPort:(NSPort *)port;
@end


#import "TPerson.h"

@interface TPerson()
@property (nonatomic, strong) NSPort *bPort;
@end

@implementation TPerson
- (void)personLaunchThreadWithPort:(NSPort *)port{
    @autoreleasepool {
        // 设置子线程名字
        [[NSThread currentThread] setName:@"TPersonThread"];
        // 开启runloop
        [[NSRunLoop currentRunLoop] run];
        // 创建自己port
        self.bPort = [NSMachPort port];
        // 完成向主线程port发送消息
        
        NSData *data = [@"portPass" dataUsingEncoding:NSUTF8StringEncoding];

        NSMutableArray *array  =[[NSMutableArray alloc]initWithArray:@[data,self.bPort]];
        // 发送消息到A线程
        // 第一个参数:发送时间。
        // msgid 消息标识。
        // components,发送消息附带参数。
        // reserved:为头部预留的字节数
        [port sendBeforeDate:[NSDate date]
                       msgid:10086
                  components:array
                        from:self.bPort
                     reserved:0];
    }
}
#pragma mark - NSMachPortDelegate

- (void)handlePortMessage:(NSPortMessage *)message{
    NSLog(@"VC == %@",[NSThread currentThread]);
    NSLog(@"从person 传过来一些信息:");
//    NSLog(@"localPort == %@",[message valueForKey:@"localPort"]);
//    NSLog(@"remotePort == %@",[message valueForKey:@"remotePort"]);
//    NSLog(@"receivePort == %@",[message valueForKey:@"receivePort"]);
//    NSLog(@"sendPort == %@",[message valueForKey:@"sendPort"]);
//    NSLog(@"msgid == %@",[message valueForKey:@"msgid"]);
//    NSLog(@"components == %@",[message valueForKey:@"components"]);
    
    NSArray *messageArr = [message valueForKey:@"components"];
    NSString *dataStr   = [[NSString alloc] initWithData:messageArr.firstObject  encoding:NSUTF8StringEncoding];
    NSLog(@"传过来一些信息 :%@",dataStr);
    NSPort  *destinPort = [message valueForKey:@"remotePort"];
    
    if(!destinPort || ![destinPort isKindOfClass:[NSPort class]]){
        NSLog(@"传过来的数据有误");
        return;
    }
}

Tips

atomicnonatomic

一般iOS开发中,关于线程相关需要注意的是:

上一篇下一篇

猜你喜欢

热点阅读