3-2 iOS 多线程 NSThread

本文详细介绍了如何使用NSThread进行多线程编程,并演示了通过加锁解决线程同步问题的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

NSThread

如何用?

- (void)nsthreadDemo {
    //创建方法
    //1 动态创建  需要调用start启动线程
    NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(threadMethod) object:nil];
    thread1.name = @"我是线程1售票窗口";
    //2 静态创建 没有返回值 如果需要获取到用这个方法创建的线程 需要在selector中通过currentThread获取
//    [NSThread detachNewThreadSelector:@selector(threadMethod) toTarget:self withObject:nil];
    
    NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(threadMethod) object:nil];
    thread2.name = @"我是线程2售票窗口";
    
    NSThread *thread3 = [[NSThread alloc] initWithTarget:self selector:@selector(threadMethod) object:nil];
    thread3.name = @"我是线程3售票窗口";
    //设置线程优先级
//    NSQualityOfServiceUserInteractive:最高优先级,用于用户交互事件
//    NSQualityOfServiceUserInitiated:次高优先级,用于用户需要马上执行的事件
//    NSQualityOfServiceDefault:默认优先级,主线程和没有设置优先级的线程都默认为这个优先级
//    NSQualityOfServiceUtility:普通优先级,用于普通任务
//    NSQualityOfServiceBackground:最低优先级,用于不重要的任务
//    [thread1 setQualityOfService:NSQualityOfServiceUserInteractive];
    //线程开启
    [thread1 start];
    [thread2 start];
    [thread3 start];
    //线程通信
    //在主线程中执行
//    [self performSelectorOnMainThread:@selector(mainThreadMethod) withObject:nil waitUntilDone:YES];
    //开辟一条线程执行
//    [self performSelectorInBackground:@selector(threadMethod) withObject:nil];
    //在当前线程执行
//    [self performSelector:@selector(threadMethod)];
//    [self performSelector:@selector(threadMethod) withObject:nil];
//    [self performSelector:@selector(threadMethod) withObject:nil afterDelay:2.0];//在当前线程延时执行
    //在指定线程中执行
//    [self performSelector:@selector(threadMethod) onThread:thread1 withObject:nil waitUntilDone:YES];
    
}

- (void)threadMethod {
    //线程暂停
//    [NSThread sleepForTimeInterval:1.0];
//    [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
    
    //线程取消 只是标记线程是否需要退出 并不会马上停止和退出线程
//    [[NSThread currentThread] cancel];
    
    //线程退出
//    [NSThread exit];
    
//    NSLog(@"当前线程:%@",[NSThread currentThread]);
    
    //线程同步
    
    /*
     如上篇GCD同步问题描述,我们现在解决一个售票问题,假如有二十张票,同时三个窗口在售卖。我们先看看直接三个线程访问这个票源会出现什么问题。
     */
    
    while (1) {
        @synchronized(self) {
            if (tickCount > 0) {
                tickCount--; //模拟卖出一张票
                NSLog(@"当前线程:%@  剩余票数%d",[NSThread currentThread],tickCount);
                [NSThread sleepForTimeInterval:1.2];
            }else {
                NSLog(@"销售完毕");
                break;
            }
        }
    }
    
}

处理线程同步问题:

如果不给会竞争资源的地方加锁

1.如果资源操作不耗时

票数不会错乱,但是会存在两个或多个线程同一时间访问同一张票

2.资源操作耗时

票数错乱。并且存在两个或多个线程同一时间访问同一张票

当前线程:<NSThread: 0x604000271700>{number = 3, name = 我是线程1售票窗口}  剩余票数19
2018-04-08 11:29:17.911633+0800 OC基础[34398:8677737] 当前线程:<NSThread: 0x604000271400>{number = 4, name = 我是线程2售票窗口}  剩余票数18
2018-04-08 11:29:17.911753+0800 OC基础[34398:8677738] 当前线程:<NSThread: 0x604000271640>{number = 5, name = 我是线程3售票窗口}  剩余票数17
2018-04-08 11:29:18.016563+0800 OC基础[34398:8677736] 当前线程:<NSThread: 0x604000271700>{number = 3, name = 我是线程1售票窗口}  剩余票数16
2018-04-08 11:29:18.016665+0800 OC基础[34398:8677737] 当前线程:<NSThread: 0x604000271400>{number = 4, name = 我是线程2售票窗口}  剩余票数15
2018-04-08 11:29:18.017573+0800 OC基础[34398:8677738] 当前线程:<NSThread: 0x604000271640>{number = 5, name = 我是线程3售票窗口}  剩余票数14
2018-04-08 11:29:18.122791+0800 OC基础[34398:8677736] 当前线程:<NSThread: 0x604000271700>{number = 3, name = 我是线程1售票窗口}  剩余票数13
2018-04-08 11:29:18.122875+0800 OC基础[34398:8677738] 当前线程:<NSThread: 0x604000271640>{number = 5, name = 我是线程3售票窗口}  剩余票数11
2018-04-08 11:29:18.122929+0800 OC基础[34398:8677737] 当前线程:<NSThread: 0x604000271400>{number = 4, name = 我是线程2售票窗口}  剩余票数12
2018-04-08 11:29:18.228322+0800 OC基础[34398:8677736] 当前线程:<NSThread: 0x604000271700>{number = 3, name = 我是线程1售票窗口}  剩余票数9
2018-04-08 11:29:18.228322+0800 OC基础[34398:8677738] 当前线程:<NSThread: 0x604000271640>{number = 5, name = 我是线程3售票窗口}  剩余票数9
2018-04-08 11:29:18.228322+0800 OC基础[34398:8677737] 当前线程:<NSThread: 0x604000271400>{number = 4, name = 我是线程2售票窗口}  剩余票数9
2018-04-08 11:29:18.332442+0800 OC基础[34398:8677738] 当前线程:<NSThread: 0x604000271640>{number = 5, name = 我是线程3售票窗口}  剩余票数8
2018-04-08 11:29:18.332512+0800 OC基础[34398:8677736] 当前线程:<NSThread: 0x604000271700>{number = 3, name = 我是线程1售票窗口}  剩余票数7
2018-04-08 11:29:18.332607+0800 OC基础[34398:8677737] 当前线程:<NSThread: 0x604000271400>{number = 4, name = 我是线程2售票窗口}  剩余票数6
2018-04-08 11:29:18.436135+0800 OC基础[34398:8677736] 当前线程:<NSThread: 0x604000271700>{number = 3, name = 我是线程1售票窗口}  剩余票数5
2018-04-08 11:29:18.437151+0800 OC基础[34398:8677738] 当前线程:<NSThread: 0x604000271640>{number = 5, name = 我是线程3售票窗口}  剩余票数4
2018-04-08 11:29:18.437151+0800 OC基础[34398:8677737] 当前线程:<NSThread: 0x604000271400>{number = 4, name = 我是线程2售票窗口}  剩余票数3
2018-04-08 11:29:18.540461+0800 OC基础[34398:8677736] 当前线程:<NSThread: 0x604000271700>{number = 3, name = 我是线程1售票窗口}  剩余票数2
2018-04-08 11:29:18.542040+0800 OC基础[34398:8677738] 当前线程:<NSThread: 0x604000271640>{number = 5, name = 我是线程3售票窗口}  剩余票数0
2018-04-08 11:29:18.542087+0800 OC基础[34398:8677737] 当前线程:<NSThread: 0x604000271400>{number = 4, name = 我是线程2售票窗口}  剩余票数0

以上是资源耗时较少的情况。资源耗时多的情况请自行测试。


加锁后:

当前线程:<NSThread: 0x60000046c4c0>{number = 3, name = 我是线程1售票窗口剩余票数19

2018-04-12 10:00:16.688413+0800 OC基础[87234:11885173] 当前线程:<NSThread: 0x60000046c500>{number = 4, name = 我是线程2售票窗口剩余票数18

2018-04-12 10:00:17.888849+0800 OC基础[87234:11885174] 当前线程:<NSThread: 0x60000046c0c0>{number = 5, name = 我是线程3售票窗口剩余票数17

2018-04-12 10:00:19.092933+0800 OC基础[87234:11885172] 当前线程:<NSThread: 0x60000046c4c0>{number = 3, name = 我是线程1售票窗口剩余票数16

2018-04-12 10:00:20.298277+0800 OC基础[87234:11885173] 当前线程:<NSThread: 0x60000046c500>{number = 4, name = 我是线程2售票窗口剩余票数15

2018-04-12 10:00:21.499725+0800 OC基础[87234:11885174] 当前线程:<NSThread: 0x60000046c0c0>{number = 5, name = 我是线程3售票窗口剩余票数14

2018-04-12 10:00:22.703571+0800 OC基础[87234:11885172] 当前线程:<NSThread: 0x60000046c4c0>{number = 3, name = 我是线程1售票窗口剩余票数13

2018-04-12 10:00:23.907196+0800 OC基础[87234:11885173] 当前线程:<NSThread: 0x60000046c500>{number = 4, name = 我是线程2售票窗口剩余票数12

2018-04-12 10:00:25.109659+0800 OC基础[87234:11885174] 当前线程:<NSThread: 0x60000046c0c0>{number = 5, name = 我是线程3售票窗口剩余票数11

2018-04-12 10:00:26.312094+0800 OC基础[87234:11885172] 当前线程:<NSThread: 0x60000046c4c0>{number = 3, name = 我是线程1售票窗口剩余票数10

2018-04-12 10:00:27.516949+0800 OC基础[87234:11885173] 当前线程:<NSThread: 0x60000046c500>{number = 4, name = 我是线程2售票窗口剩余票数9

2018-04-12 10:00:28.722266+0800 OC基础[87234:11885174] 当前线程:<NSThread: 0x60000046c0c0>{number = 5, name = 我是线程3售票窗口剩余票数8

2018-04-12 10:00:29.923215+0800 OC基础[87234:11885172] 当前线程:<NSThread: 0x60000046c4c0>{number = 3, name = 我是线程1售票窗口剩余票数7

2018-04-12 10:00:31.126571+0800 OC基础[87234:11885173] 当前线程:<NSThread: 0x60000046c500>{number = 4, name = 我是线程2售票窗口剩余票数6

2018-04-12 10:00:32.329425+0800 OC基础[87234:11885174] 当前线程:<NSThread: 0x60000046c0c0>{number = 5, name = 我是线程3售票窗口剩余票数5

2018-04-12 10:00:33.532408+0800 OC基础[87234:11885172] 当前线程:<NSThread: 0x60000046c4c0>{number = 3, name = 我是线程1售票窗口剩余票数4

2018-04-12 10:00:34.737175+0800 OC基础[87234:11885173] 当前线程:<NSThread: 0x60000046c500>{number = 4, name = 我是线程2售票窗口剩余票数3

2018-04-12 10:00:35.941494+0800 OC基础[87234:11885174] 当前线程:<NSThread: 0x60000046c0c0>{number = 5, name = 我是线程3售票窗口剩余票数2

2018-04-12 10:00:37.145875+0800 OC基础[87234:11885172] 当前线程:<NSThread: 0x60000046c4c0>{number = 3, name = 我是线程1售票窗口剩余票数1

2018-04-12 10:00:38.353758+0800 OC基础[87234:11885173] 当前线程:<NSThread: 0x60000046c500>{number = 4, name = 我是线程2售票窗口剩余票数0

2018-04-12 10:00:39.561668+0800 OC基础[87234:11885174] 销售完毕

2018-04-12 10:00:39.561895+0800 OC基础[87234:11885172] 销售完毕

2018-04-12 10:00:39.562236+0800 OC基础[87234:11885173] 销售完毕

完美解决。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值