OC基础知识点之-多线程(一)多线程基础

2021-08-14  本文已影响0人  iOS_子矜

线程与进程

线程

进程

线程和进程的联系

多线程的优点和缺点

优点

缺点

多线程的实际实现

先介绍一个概念:时间片。时间片:CPU在多个任务之间进行快速切换,这个时间间隔就是时间片。

单核和多核

多线程的内存消耗

官方文档对多线程的内存消耗有个说明官方文档传送门

多线程处理方案

线程生命周期

线程池的原理

饱和策略

四种拒绝策略均实现了RejectedExecutionHandler接⼝

线程优先级

地址越高,其优先级越高,也就是说用户操作行为的优先级是最高的。但注意:

锁作用

锁使用的注意点

互斥锁和自旋锁

自旋锁

自旋锁成员

自旋锁包含:atomic, OSSpinLock, dispatch_semaphore_t

定义:

定义:是一种用于保护多线程共享资源的锁,与一般互斥锁(mutex)不同之处在于当自旋锁尝试获取锁时以忙等待(busy waiting)的形式不断地循环检查锁是否可用。当上一个线程的任务没有执行完毕的时候(被锁住),那么下一个线程会一直等待(不会睡眠),当上一个线程的任务执行完毕,下一个线程会立即执行

自旋锁会忙等: 所谓忙等,即在访问被锁资源时,调用者线程不会休眠,而是不停循环在那里,直到被锁资源释放锁。

使用场景

互斥锁

互斥锁成员

互斥锁包含:@synchronized,NSLock, pthread_mutex, NSConditionLock, NSCondition, NSRecursiveLock

定义

定义:互斥锁当上一个线程的任务没有执行完毕的时候(被锁住),那么下一个线程会进入睡眠状态等待任务执行完毕,当上一个线程的任务执行完毕,下一个线程会自动唤醒然后执行任务。

互斥锁会休眠: 所谓休眠,即在访问被锁资源时,调用者线程会休眠,此时cpu可以调度其他线程工作。直到被锁资源释放锁。此时会唤醒休眠线程。

使用场景

atomic与nonatomic 的区别

nonatomic ⾮原⼦属性

atomic 原⼦属性

说明:使用atomic修饰属性时,编译器在生成getter和setter方法时,在getter和setter方法内部实现进行加锁操作,这么做的目的是为了保证属性读写的安全性和完整性,也就是说对于属性值得存取是线程安全的。但这个不能保证操作这个属性的时候是线程安全的

iOS 开发的建议

线程和Runloop的关系

延伸

端口通讯:NSPort

下面我们举例子来展示多线程的端口通讯,通过KCPerson对象跟ViewController进行发送消息的例子

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

- (void)handlePortMessage:(NSPortMessage *)message {
    NSLog(@"VC == %@",[NSThread currentThread]);
    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;
    }
    NSData *data = [@"VC收到!!!" dataUsingEncoding:NSUTF8StringEncoding];
    NSMutableArray *array  =[[NSMutableArray alloc]initWithArray:@[data,self.myPort]];
    // 非常重要,如果你想在Person的port接受信息,必须加入到当前主线程的runloop
    [[NSRunLoop currentRunLoop] addPort:destinPort forMode:NSDefaultRunLoopMode];

    NSLog(@"VC == %@",[NSThread currentThread]);

    BOOL success = [destinPort sendBeforeDate:[NSDate date]
                                        msgid:10010
                                   components:array
                                         from:self.myPort
                                     reserved:0];
    NSLog(@"%d",success);

}
// Person.m
- (void)personLaunchThreadWithPort:(NSPort *)port{

    NSLog(@"VC 响应了Person里面");
    @autoreleasepool {
        //1\. 保存主线程传入的port
        self.vcPort = port;
        //2\. 设置子线程名字
        [[NSThread currentThread] setName:@"KCPersonThread"];
        //3\. 开启runloop
        [[NSRunLoop currentRunLoop] run];
        //4\. 创建自己port
        self.myPort = [NSMachPort port];
        //5\. 设置port的代理回调对象
        self.myPort.delegate = self;
        //6\. 完成向主线程port发送消息
        [self sendPortMessage];
    }
}
/**
 *   完成向主线程发送port消息
 */

- (void)sendPortMessage {
    NSData *data1 = [@"AAAA" dataUsingEncoding:NSUTF8StringEncoding];
    NSData *data2 = [@"BBBB" dataUsingEncoding:NSUTF8StringEncoding];
    NSMutableArray *array  =[[NSMutableArray alloc]initWithArray:@[data1,self.myPort]];
    // 发送消息到VC的主线程
    // 第一个参数:发送时间。
    // msgid 消息标识。
    // components,发送消息附带参数。
    // reserved:为头部预留的字节数
    [self.vcPort sendBeforeDate:[NSDate date]
                          msgid:10086
                     components:array
                           from:self.myPort
                       reserved:0];
}

- (void)handlePortMessage:(NSPortMessage *)message{

    NSLog(@"person:handlePortMessage  == %@",[NSThread currentThread]);

    NSLog(@"从VC 传过来一些信息:");
    NSLog(@"components == %@",[message valueForKey:@"components"]);
    NSLog(@"receivePort == %@",[message valueForKey:@"receivePort"]);
    NSLog(@"sendPort == %@",[message valueForKey:@"sendPort"]);
    NSLog(@"msgid == %@",[message valueForKey:@"msgid"]);
}
运行打印:

注意:

上一篇 下一篇

猜你喜欢

热点阅读