一个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 = ; i < ; i ++) {
if (i == ) {
//[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
[NSThread sleepForTimeInterval:2.0];//阻塞状态 移出线程池
//两秒钟过后 再次进入就绪状态 等待调度进入运行状态
}
if (i == ) {
//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 = ;
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 () {
NSInteger count = self.totalCount;
if (count > ) {
for (NSInteger i = ; i < ; i ++) { }
//卖出去一张票
self.totalCount = count - ;
NSLog(@"%@ 卖出去一张票 还剩%zd张票",[NSThread currentThread].name,self.totalCount);
}else {
NSLog(@"票卖完了");
break;
}
} }

打印结果

-- ::38.600491+ NSThreadDemo[:] 售票员A 卖出去一张票  还剩999张票
-- ::38.600493+ NSThreadDemo[:] 售票员B 卖出去一张票 还剩999张票
-- ::38.600519+ NSThreadDemo[:] 售票员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 = ;
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 () {
//锁必须是全局唯一的
@synchronized(self) {
NSInteger count = self.totalCount;
if (count > ) {
for (NSInteger i = ; i < ; i ++) { }
//卖出去一张票
self.totalCount = count - ;
NSLog(@"%@ 卖出去一张票 还剩%zd张票",[NSThread currentThread].name,self.totalCount);
}else {
NSLog(@"票卖完了");
break;
}
}
} }

互斥锁的优缺点

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

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

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

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

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

原子和非原子属性

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

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

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

 @property (assign, atomic) int age;

 - (void)setAge:(int)age
{ @synchronized(self) {
_age = age;
}
}

原子和非原子属性的选择

nonatomic和atomic对比

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

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

iOS开发的建议

所有属性都声明为nonatomic

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

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

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

  1. iOS 多线程(NSThread、GCD、NSOperation)

    ios中得多线程技术主要使用3种:NSThread.NSOperation和GCD 一.NSThread: 最轻量级方法,但是不安全需要手动加锁,需要自己管理生命周期 NSThread的使用方法有2种 ...

  2. iOS多线程开发--NSThread NSOperation GCD

    多线程 当用户播放音频.下载资源.进行图像处理时往往希望做这些事情的时候其他操作不会被中 断或者希望这些操作过程中更加顺畅.在单线程中一个线程只能做一件事情,一件事情处理不完另一件事就不能开始,这样势 ...

  3. IOS多线程(NSThread)

    1.创建方法 使用NSThread创建线程主要有两个个方法,分别如下 NSThread* myThread = [[NSThread alloc] initWithTarget:self   sele ...

  4. iOS GCD NSOperation NSThread等多线程各种举例详解(拷贝)

    2年多的iOS之路匆匆而过,期间也拜读来不少大神的博客,近来突然为自己一直做伸手党感到羞耻,是时候回馈社会.回想当年自己还是小白的时候,照着一些iOS多线程教程学,也只是照抄,只知其然.不知其所以然. ...

  5. iOS多线程编程之NSThread的使用

      目录(?)[-] 简介 iOS有三种多线程编程的技术分别是 三种方式的有缺点介绍 NSThread的使用 NSThread 有两种直接创建方式 参数的意义 PS不显式创建线程的方法 下载图片的例子 ...

  6. iOS多线程编程之NSThread的使用(转)

    本文由http://blog.csdn.net/totogo2010/原创 1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThread 2.Cocoa NSOperation  ...

  7. iOS 多线程学习笔记 —— NSThread

    本文复制.参考自文章:iOS多线程编程之NSThread的使用  ,主要为了加强个人对知识的理解和记忆,不做他用.原作者声明: 著作权声明:本文由http://blog.csdn.net/totogo ...

  8. [转]iOS多线程编程之NSThread的使用

    1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThread 2.Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue ...

  9. iOS 多线程 简单学习NSThread NSOperation GCD

    1:首先简单介绍什么叫线程 可并发执行的,拥有最小系统资源,共享进程资源的基本调度单位. 共用堆,自有栈(官方资料说明iOS主线程栈大小为1M,其它线程为512K). 并发执行进度不可控,对非原子操作 ...

随机推荐

  1. android-pull方式解析xml文件以及XML文件的序列化

    android解析XML ---------------------------基础要像磐石 在android平台上可以使用SAX.DOM和自带的Pull解析器解析xml文件,本文主要介绍使用pull ...

  2. 转:C#中Monitor对象与Lock关键字的区别分析

    Monitor对象1.Monitor.Enter(object)方法是获取 锁,Monitor.Exit(object)方法是释放锁,这就是Monitor最常用的两个方法,当然在使用过程中为了避免获取 ...

  3. Angular2升级到Angular4

    angular4终于在两天前发布了正式版本,那么怎么升级呢?其实angular2和angular4之间属于平滑过渡,并不像1和2之间颠覆性的重写代码. npm uninstall -g @angula ...

  4. iOS SDK具体解释之NSCopying协议

    原创blog,转载请注明出处 http://blog.csdn.net/hello_hwc?viewmode=contents 欢迎关注我的iOS SDK具体解释专栏 http://blog.csdn ...

  5. Python模块学习之fabric

    fabric是一个运维经常使用到的一个模块.但是我在python3环境下安装fabric就遇到了坑! 安装包名称是fabric3而不是fabric! pip install fabric3 利用fab ...

  6. 如何获取UA

    function whatBrowser() { document.Browser.Name.value=navigator.appName; document.Browser.Version.val ...

  7. struts2的validate在使用过程中的一个问题

    在项目中有一个新增客户信息的的功能:  1.在进入加入页面:add.jsp页面之前,要调用一个add_init.do来获取省份信息列表以供在add.jsp进行选择. 2.add页面填写完毕以后.提交给 ...

  8. Java并发编程(十三)同步容器类

    同步容器类 Vector.HashTable,我用的很少:Vecotr的实现和ArrayList挺接近的,不同的是Vector中很多的方法都用synchronized进行了同步.在不强调线程安全地时候 ...

  9. LeetCode447. Number of Boomerangs

    Description Given n points in the plane that are all pairwise distinct, a "boomerang" is a ...

  10. Android startActivity()和onActivityResult()使用总结(转载)

    有三个Activity: A.java ,B.java ,C.java Activity之间的跳转常用方法: 1. startActivity(Intent intent); 该方法只用于启动新的Ac ...