一个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. 程序员取悦女票的正确姿势---Tip1(iOS美容篇)

    代码地址如下:http://www.demodashi.com/demo/11695.html 前言 女孩子都喜欢用美图工具进行图片美容,近来无事时,特意为某人写了个自定义图片滤镜生成器,安装到手机即 ...

  2. iDempiere的用户密码加密处理(AD_User.Password)(Postgresql 9.1)

    怀揣着为中小企业量身定做一整套开源软件解决方案的梦想开始了一个网站的搭建.http://osssme.org/ 首先对Postgresql数据库进行加密处理. 参考网页:francs写的:Postgr ...

  3. lucene 加速索引建立速度

    加速 lucene 索引建立速度 ImproveIndexingSpeed

  4. filebeat.service

    # # filebeat systemd service # [Unit] Description=Filebeat Documentation=https://www.elastic.co/guid ...

  5. 利用python批量缩放图片

    废话少说,上代码: import matplotlib as mpl mpl.use('Agg') import os import matplotlib.pyplot as plt from sci ...

  6. Atitit.虚拟机与指令系统的设计

    Atitit.虚拟机与指令系统的设计 1. 两种计算模型  ,堆栈机和状态机(基于寄存器的虚拟机1 1.1.1. 堆栈机1 1.1.2. 状态机2 2. 为什么状态机比堆栈机快呢?3 2.1. Sta ...

  7. Atitit.常用语言的常用内部api 以及API兼容性对源码级别可移植的重要性 总结

    Atitit.常用语言的常用内部api 以及API兼容性对源码级别可移植的重要性 总结 1.1. 要兼容的重要语言api1 1.2. 常用基础api分类 core api1 1.3. 比较常用的扩展库 ...

  8. Android JNI和NDK学习(01)--搭建NDK开发环境(转)

    本文转自:http://www.cnblogs.com/skywang12345/archive/2013/05/23/3095013.html 本文主要介绍“JNI”.“Android NDK”以及 ...

  9. 2. Add Two Numbers【medium】

    2. Add Two Numbers[medium] You are given two non-empty linked lists representing two non-negative in ...

  10. 234. Palindrome Linked List【easy】

    234. Palindrome Linked List[easy] Given a singly linked list, determine if it is a palindrome. Follo ...