iOS 多线程之 NSThread的基本使用

一个NSThread对象就代表一条线程 下面是NSThread开启线程的方法

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self openThreadWithNSThread];
    [NSThread mainThread];//获取主线程
    [NSThread currentThread]; //获取当前线程
}

- (void) openThreadWithNSThread {
    /*
     *第一个参数 目标对象 self
     *第二个参数 方法选择器 调用的方法
     *第三个参数 前面调用方法需要传递的参数 可以为nil
     */
    //第一种方式
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadAction:) object:@"ABC"];
    thread.name = @"线程1";
    //0.0-1.0之间 1.0最高 0.0最低 默认0.5 越高线程被调用的频率越大
    thread.threadPriority = 1.0;
    [thread start];//需要手动调用启动线程
    //第二种方式
    [NSThread detachNewThreadSelector:@selector(threadAction:) toTarget:self withObject:@"abc2"];//自动启动线程

    //第三种方式
    [self performSelectorInBackground:@selector(threadAction:) withObject:@"开启一条后台线程"];//开启一条后台线程

    //block方式
    NSThread *thread1 = [[NSThread alloc] initWithBlock:^{
      NSLog(@"%@",[NSThread currentThread]);
    }];
    thread1.name = @"线程2";
    thread1.threadPriority = 0.5;
    [thread start];

    //或者
    [NSThread detachNewThreadWithBlock:^{
        NSLog(@"%@",[NSThread currentThread]);
    }];

}

- (void) threadAction:(NSString *)params {
    NSLog(@"%@ and %@",params,[NSThread currentThread].name);
}

NSThread 创建线程的生命周期

当线程中的任务执行完毕后 线程被释放掉 可以继承NSThread创建一个新类 重写dealloc方法来验证

线程的状态

当线程处于就绪状态时线程会被移到可调度线程池里面(CPU只调度此线程池里面的线程),当处于阻塞状态时,线程会被移出可调度线程池,当处于死亡状态时 先移出线程池,再从内存中释放。

- (void)threadStatus {
    //创建线程 在内存中创建一个线程 (新建状态)
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadAction1) object:nil];
    [thread start]; //就绪状态 会被放倒可调度线程池里面 只有在可调度线程池里面的线程才是可以被CPU调度的

}
//一旦线程死亡了 就不能再次开启任务
- (void)threadAction1 {
    //运行状态
    for (NSInteger i = 0; i < 10000; i ++) {
        if (i == 5000) {
            //[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
            [NSThread sleepForTimeInterval:2.0];//阻塞状态 移出线程池
            //两秒钟过后 再次进入就绪状态 等待调度进入运行状态
        }
        if (i == 8000) {
            //break;//任务完成 自然死亡
            [NSThread exit]; //废除线程强制进入死亡状态
        }
        NSLog(@"%@",[NSThread currentThread]);
    }
    //执行完方法之后死亡状态
}

线程的安全 也非常重要 这里介绍一种方法 后面会着重介绍

多线程的安全隐患

资源共享

1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源 比如多个线程访问同一个对象 同一个变量 同一个文件 此时就很容易引发数据错乱和数据安全问题.

安全隐患原因分析

安全隐患的解决

问题代码

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic,strong) NSThread *threadA;//售票员A
@property (nonatomic,strong) NSThread *threadB;//售票员B
@property (nonatomic,strong) NSThread *threadC;//售票员C
@property (nonatomic,assign) NSInteger totalCount;

@end

@implementation ViewController

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    //设置总票数
    self.totalCount = 1000;
    self.threadA = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.threadA.name = @"售票员A";
    [self.threadA start];
    self.threadB = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.threadB.name = @"售票员B";
    [self.threadB start];
    self.threadC = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.threadC.name = @"售票员C";
    [self.threadC start];
}

//售票
- (void)saleTicket {
    while (1) {
        NSInteger count = self.totalCount;
        if (count > 0) {
            for (NSInteger i = 0; i < 100000; i ++) {

            }
            //卖出去一张票
            self.totalCount = count - 1;
            NSLog(@"%@ 卖出去一张票  还剩%zd张票",[NSThread currentThread].name,self.totalCount);
        }else {
            NSLog(@"票卖完了");
            break;
        }
    }

}

打印结果

2018-03-05 22:28:38.600491+0800 NSThreadDemo[1016:86284] 售票员A 卖出去一张票  还剩999张票
2018-03-05 22:28:38.600493+0800 NSThreadDemo[1016:86285] 售票员B 卖出去一张票  还剩999张票
2018-03-05 22:28:38.600519+0800 NSThreadDemo[1016:86286] 售票员C 卖出去一张票  还剩999张票

问题解决代码

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic,strong) NSThread *threadA;//售票员A
@property (nonatomic,strong) NSThread *threadB;//售票员B
@property (nonatomic,strong) NSThread *threadC;//售票员C
@property (nonatomic,assign) NSInteger totalCount;

@end

@implementation ViewController

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    //设置总票数
    self.totalCount = 1000;
    self.threadA = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.threadA.name = @"售票员A";
    [self.threadA start];
    self.threadB = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.threadB.name = @"售票员B";
    [self.threadB start];
    self.threadC = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.threadC.name = @"售票员C";
    [self.threadC start];
}

//售票
- (void)saleTicket {
    while (1) {
        //锁必须是全局唯一的
        @synchronized(self) {
            NSInteger count = self.totalCount;
            if (count > 0) {
                for (NSInteger i = 0; i < 100000; i ++) {

                }
                //卖出去一张票
                self.totalCount = count - 1;
                NSLog(@"%@ 卖出去一张票  还剩%zd张票",[NSThread currentThread].name,self.totalCount);
            }else {
                NSLog(@"票卖完了");
                break;
            }
        }
    }

}

互斥锁的优缺点

优点:能有效防止因多线程抢夺资源造成的数据安全问题

缺点:需要消耗大量的CPU资源

互斥锁的使用前提:多条线程抢夺同一块资源

相关专业术语:线程同步,多条线程按顺序地执行任务

互斥锁,就是使用了线程同步技术

原子和非原子属性

OC在定义属性时有nonatomic和atomic两种选择

atomic:原子属性,为setter方法加锁(默认就是atomic)

nonatomic:非原子属性,不会为setter方法加锁

1 @property (assign, atomic) int age;
2
3 - (void)setAge:(int)age
4 {
5
6     @synchronized(self) {
7        _age = age;
8     }
9}

原子和非原子属性的选择

nonatomic和atomic对比

atomic:线程安全,需要消耗大量的资源(并非是真正的线程安全 更准确的说应该是读写安全,但并不是线程安全的,因为别的线程还能进行读写之外的其他操作。线程安全需要开发者自己来保证。)

nonatomic:非线程安全,适合内存小的移动设备

iOS开发的建议

所有属性都声明为nonatomic

尽量避免多线程抢夺同一块资源

尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力

原文地址:https://www.cnblogs.com/huanying2000/p/8511844.html

时间: 2024-08-16 20:33:39

iOS 多线程之 NSThread的基本使用的相关文章

iOS多线程-NSThread

本文转载自嘟嘟夜未央的博文:http://www.cnblogs.com/huluo666/p/3645889.html,修改了部分代码和贴图,如有侵犯版权请与我联系删除. 多线程这个概念的接触是蛮早的时候了,当时还是单核单CPU的时候,Thread这个概念已经出现了,当时比较流行的方案是时间片轮流,线程可以优先级抢占,但一次只能运行一个线程,实际上多线程是不能真正并行处理的,只是宏观上表现的多线程在齐头并进.现在硬件进步了很多,多核的CPU时代来临了,于是线程开始了真正意义上的并行处理,多线程

iOS多线程开发——NSThread浅析

在IOS开发中,多线程的实现方式主要有三种,NSThread.NSOperation和GCD,我前面博客中对NSOperation和GCD有了较为详细的实现,可以参考<iOS多线程开发--NSOperation/NSOperationQueue浅析><iOS多线程开发--GCD的使用与多线程开发浅析>.以及对于多线程中的同步异步,并行串行等概念,我在<GCD实践--串行队列/并发队列与iOS多线程详解>中也有较为详细的讲解.为了学习的完整性,今天我们主要从代码层面来实现

ios多线程(NSThread、GCD、NSOperation)

ios中得多线程技术主要使用3种:NSThread.NSOperation和GCD 一.NSThread: 最轻量级方法,但是不安全需要手动加锁,需要自己管理生命周期 NSThread的使用方法有2种: // 第一种,需要start 1 NSThread *th1 = [[NSThread alloc] initWithTarget:self selector:@selector(btnClick) object:nil]; 2     [th1 setName:@"线程1"]; 3 

iOS多线程开发--NSThread NSOperation GCD

多线程 当用户播放音频.下载资源.进行图像处理时往往希望做这些事情的时候其他操作不会被中 断或者希望这些操作过程中更加顺畅.在单线程中一个线程只能做一件事情,一件事情处理不完另一件事就不能开始,这样势必影响用户体验.早在单核处理器时期 就有多线程,这个时候多线程更多的用于解决线程阻塞造成的用户等待(通常是操作完UI后用户不再干涉,其他线程在等待队列中,CPU一旦空闲就继续执行, 不影响用户其他UI操作),其处理能力并没有明显的变化.如今无论是移动操作系统还是PC.服务器都是多核处理器,于是“并行

IOS多线程开发-NSThread原理及演示

// 创建线程方式1 - (void)test1 { // 实例化一个线程对像 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; // 让线程开始工作,启动线程, 在新开的线程执行run方法 [thread start]; } // 创建线程方式2 - (void)test2 { NSLog(@"---%@", [NSThread currentTh

IOS多线程(NSThread,NSOperation,Grand Central Dispatch)

•NSThread: –优点:NSThread 比其他两个轻量级,使用简单 –缺点:需要自己管理线程的生命周期.线程同步.加锁.睡眠以及唤醒等.线程同步对数据的加锁会有一定的系统开销 •NSOperation: –不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上 –NSOperation是面向对象的 - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOO

iOS 多线程( GCD NSThread )

1.NSThread ①.开线程的几种方式 *先创建, 后启动 //开启线程 NSThread *thread =[[NSThread alloc]initWithTarget:self selector:@selector(run) object:nil]; //启动 [thread start]; //直接启动 [NSThread detachNewThreadSelector:@selector(<#selector#>) toTarget:self withObject:nil]; ②

iOS多线程的初步研究(一)-- NSThread

iOS多线程的初步研究(一)-- NSThread 对于多线程的开发,iOS系统提供了多种不同的接口,先谈谈iOS多线程最基础方面的使用.产生线程的方式姑且分两类,一类是显式调用,另一类是隐式调用. 一.显示调用的类为NSThread.一般构造NSThread的线程对象可通过两种方式: 1. 初始化线程主方法: [NSThread detachNewThreadSelector:@selector(run:) toTarget:target withObject:obj];//类方法 或 NST

iOS多线程 NSThread/GCD/NSOperationQueue

http://www.cnblogs.com/kenshincui/p/3983982.html iOS开发系列--并行开发其实很容易 2014-09-20 23:34 by KenshinCui, 9738 阅读, 19 评论, 收藏,  编辑 --多线程开发 概览 大家都知道,在开发过程中应该尽可能减少用户等待时间,让程序尽可能快的完成运算.可是无论是哪种语言开发的程序最终往往转换成汇编语言进而解释成机器码来执行.但是机器码是按顺序执行的,一个复杂的多步操作只能一步步按顺序逐个执行.改变这种