本篇争取一篇讲清讲透,依然将通过四大方面清晰的对iOS开发中多线程的用法进行详尽的讲解:
一、什么是多线程
1)多线程执行原理
2)线程与进程
3)多线程的优缺点
二、我们为什么要用多线程编程技术
三、如何使用多线程技术
1)pthread技术
2)NSThread技术
2.1)线程属性
2.2)资源共享(抢夺)
3)GCD技术
4) NSOperation技术
四、线程的生命周期(线程状态)
一、什么是多线程
多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理(Chip-level multithreading)或同时多线程(Simultaneous multithreading)处理器。在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理(Multithreading)”。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程(*译作“执行绪”),进而提升整体处理性能。
1) 多线程执行原理
a. (单核CPU)同一时间,cpu只能处理1个线程,只有1个线程在执行
b. 多线程同时执行:是CPU快速的在多个线程之间的切换
c. cpu调度线程的时间足够快,就造成了多线程的"同时"执行
d. 如果线程数非常多,cpu会在n个线程之间切换,消耗大量的cpu资源
i. 每个线程被调度的次数会降低,线程的执行效率降低
2)线程与进程
每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。进程也可能是整个程序或者是部分程序的动态执行。线程是一组执行的集合,或者是程序的特殊段,它可以在程序里独立执行。也可以把它理解为代码运行的上下文。所以线程基本上是轻量级的进程,它负责在单个程序里执行多任务。通常由操作系统负责多个线程的调度和执行。
线程是程序中一个单一的顺序控制流程,在单个程序中同时运行多个线程完成不同的工作,称为多线程。
线程和进程的区别在于,子进程和父进程有不同的代码和数据空间,而多个线程则共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文,多线程主要是为了节约CPU时间,发挥利用,根据具体情况而定。线程的运行中需要使用计算机的内存资源和CPU。
3)多线程的优缺点
优点:
1、使用线程可以把占据时间长的程序中的任务放到后台去处理。
2、用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度。
3、程序的运行速度可能加快。
4、在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下可以释放一些珍贵的资源如内存占用等等。
5、线程上的任务执行完成后,线程会自动销毁。
缺点:
1、线程越多,cpu在调用线程上的开销就越大,如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换。
2、开启线程需要占用一定的内存空间(默认情况下,每一个线程都占512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能,更多的线程需要更多的内存空间。
3、程序设计更加复杂,比如线程间的通信、多线程的数据共享,可能会给程序带来更多的BUG,因此要小心使用。
4、线程的中止需要考虑其对程序运行的影响。
5、通常块模型数据是在多个线程间共享的,需要一个合适的锁系统替换掉数据共享。
注意:iOS 8.0后主线程的默认堆栈大小也是 512K,官方文档标注错误。
二、我们为什么要用多线程编程技术
在大多数研究领域内是要求线程调度程序要能够快速选择其中一个已就绪线程去运行,而不是一个一个运行而降低效率。所以要让调度程序去分辨线程的优先级是很重要的。在移动开发过程中,一切均已用户体验作为首要任务,这时多线程的重要性不言而喻。
一个程序运行后,默认会开启1个线程,称为“主线程”或“UI线程”,主线程一般用来刷新UI界面,处理UI事件(比如:点击、滚动、拖拽等事件)
主线程使用注意
别将耗时的操作放到主线程中
耗时操作会卡住主线程,严重影响UI的流畅度,给用户一种卡的坏体验
三、如何使用多线程技术
ios中多线程实现的多种技术方案:
POSIX 表示可移植操作系统接口(Portable Operating System Interface )-----pthread
1)pthread技术:
pthread 是 POSIX 多线程开发框架,由于是跨平台的 C 语言框架,在苹果的头文件中并没有详细的注释要查阅 pthread 有关资料,可以访问 http://baike.baidu.com
// 创建线程,并且在线程中执行 demo 函数
- (void)pthreadDemo { /**
参数:
1> 指向线程标识符的指针,C 语言中类型的结尾通常 _t/Ref,而且不需要使用 *
2> 用来设置线程属性
3> 新建立的线程执行代码的函数
4> 运行函数的参数 返回值:
- 若线程创建成功,则返回0
- 若线程创建失败,则返回出错编号 在混合开发时,如果在 C 和 OC 之间传递数据,需要使用 __bridge 进行桥接,桥接的目的就是为了告诉编译器如何管理内存
*/
pthread_t threadId = NULL;
NSString *str = @"Hello Pthread"; int result = pthread_create(&threadId, NULL, demo, (__bridge void *)(str)); result ? NSLog(@"为其他任何值时代表开辟子线程失败") : NSLog(@"当result为0时表示开辟子线程成功");
} // 后台线程调用函数
void *demo(void *params) {
NSString *str = (__bridge NSString *)(params); NSLog(@"%@ - %@", [NSThread currentThread], str); return NULL;
}
C语言中pthread.h里pthread实现多线程
2)NSThread技术:
- (void)viewDidLoad {
[super viewDidLoad]; NSLog(@"主线程%@", [NSThread currentThread]);
/**
多个线程之间的执行顺序是随机的
*/ // 方式1:通过NSThread的对象方法
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(demo:) object:@"方式1"];
[thread start]; // 方式2:没有thread字眼,隐式创建并启动线程,所有 NSObject 都可以使用此方法,在其他线程执行方法
[self performSelectorInBackground:@selector(demo:) withObject:@"方式2"]; // 方式3:detachNewThreadSelector 类方法不需要启动,会自动创建线程并执行 @selector 方法
[NSThread detachNewThreadSelector:@selector(demo:) toTarget:self withObject:@"方式3"]; } - (void)demo:(NSString *)str {
NSLog(@"%@, %@", str, [NSThread currentThread]);
}
通过NSThread创建线程的三种方式
2.1)线程属性
1. name - 线程名称
2. threadPriority - 线程优先级
取值范围从 0~1.0
1.0表示优先级最高
0.0表示优先级最低
默认优先级是0.5
3. stackSize - 栈区大小
4. isMainThread - 是否主线程
2.2)资源共享(抢夺)
1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源,比如多个线程访问同一个对象、同一个变量、同一个文件当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题。如购买火车票问题:
解决方案:
#pragma mark
#pragma mark - 模拟卖票系统
- (void)sellTicket { _count = ; NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(ticket) object:nil];
thread1.name = @"t1";
[thread1 start]; NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(ticket) object:nil];
thread2.name = @"t2";
[thread2 start];
} - (void)ticket { while (YES) { // 被加锁的对象
@synchronized(self) {
if (_count > ) {
_count = self.count - ;
NSLog(@"剩余票数%ld ——%@", _count, [NSThread currentThread]);
} else {
NSLog(@"票卖没了倒霉蛋");
break;
}
}
} }
卖票系统线程同步解决线程不安全问题
-
互斥锁
:如果发现有其他线程正在执行锁定的代码,线程会进入休眠状态
,等待其他线程执行完毕,打开锁之后,线程会被唤醒
-
自旋锁
:如果发现有其他线程正在执行锁定的代码,线程会以死循环
的方式,一直等待锁定代码执行完成
线程安全
多个线程进行读写操作时,仍然能够得到正确结果,被称为线程安全,要实现线程安全,必须要用到锁、
为了得到更佳的用户体验,UIKit 不是线程安全的,所以更新 UI 的操作都必须主线程上执行!因此,主线程又被称为UI 线程。
3)GCD技术
为保证篇幅不过与杂糅,请见“IOS开发之多线程技术——GCD篇”
4) NSOperation技术
为保证篇幅不过与杂糅,请见“IOS开发之多线程技术——NSOperation篇”
四、线程的生命周期(线程状态)
新建
实例化线程对象
就绪
- (void)start;
向线程对象发送 start 消息,线程对象被加入 可调度线程池 等待 CPU 调度
detachNewThreadSelector 方法和 performSelectorInBackground 方法会直接实例化一个线程对象并加入 可调度线程池
运行
CPU 负责调度可调度线程池中线程的执行
线程执行完成之前(死亡之前),状态可能会在就绪和运行之间来回切换
就绪和运行之间的状态变化由 CPU 负责,程序员不能干预
阻塞
当满足某个预定条件时,可以使用休眠或锁阻塞线程执行
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
@synchronized(self):互斥锁
死亡:+ (void)exit
正常死亡
线程执行完毕
非正常死亡
当满足某个条件后,在线程内部自己中止执行(自杀),[NSThread exit];
当满足某个条件后,在主线程给其它线程打个死亡标记(下圣旨),让子线程自行了断.(被逼着死亡)
注意:在终止线程之前,应该注意释放之前分配的对象!
iOS开发之多线程技术的更多相关文章
-
iOS开发之多线程技术——NSOperation篇
本篇将从四个方面对iOS开发中使用到的NSOperation技术进行讲解: 一.什么是NSOperation 二.我们为什么使用NSOperation 三.在实际开发中如何使用NSOperation ...
-
iOS开发之多线程技术——GCD篇
本篇将从四个方面对iOS开发中GCD的使用进行详尽的讲解: 一.什么是GCD 二.我们为什么要用GCD技术 三.在实际开发中如何使用GCD更好的实现我们的需求 一.Synchronous & ...
-
iOS开发之多线程技术—GCD篇
本篇将从四个方面对iOS开发中GCD的使用进行详尽的讲解: 一.什么是GCD 二.我们为什么要用GCD技术 三.在实际开发中如何使用GCD更好的实现我们的需求 一.Synchronous & ...
-
iOS开发之多线程技术(NSThread、OperationQueue、GCD)
在前面的博客中如果用到了异步请求的话,也是用到的第三方的东西,没有正儿八经的用过iOS中多线程的东西.其实多线程的东西还是蛮重要的,如果对于之前学过操作系统的小伙伴来说,理解多线程的东西还是比较容易的 ...
-
iOS开发:多线程技术概述
一.概述 线程(thread):用于指代独立执行的代码段. 进程(process):用于指代一个正在运行的可执行程序,它可以包含多个线程. 任务(task):用于指代抽象的概念,表示需要执行工作. 多 ...
-
iOS开发-多线程编程技术(Thread、Cocoa operations、GCD)
简介 在软件开发中,多线程编程技术被广泛应用,相信多线程任务对我们来说已经不再陌生了.有了多线程技术,我们可以同做多个事情,而不是一个一个任务地进行.比如:前端和后台作交互.大任务(需要耗费一定的时间 ...
-
OS X 和iOS 中的多线程技术(上)
OS X 和iOS 中的多线程技术(上) 本文梳理了OS X 和iOS 系统中提供的多线程技术.并且对这些技术的使用给出了一些实用的建议. 多线程的目的:通过并发执行提高 CPU 的使用效率,进而提供 ...
-
OS X 和iOS 中的多线程技术(下)
OS X 和iOS 中的多线程技术(下) 上篇文章中介绍了 pthread 和 NSThread 两种多线程的方式,本文将继续介绍 GCD 和 NSOperation 这两种方式.. 1.GCD 1. ...
-
iOS开发-多线程开发之线程安全篇
前言:一块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源,比如多个线程访问同一个对象.同一个变量.同一个文件和同一个方法等.因此当多个线程访问同一块资源时,很容易会发生数据错误及数据不安 ...
随机推荐
-
openvpn安装
1,wget http://swupdate.openvpn.org/as/openvpn-as-2.0.10-CentOS7.x86_64.rpm 2,passwd openvpn
-
return、 return false的用法
1. return返回null,起到中断方法执行的效果,只要不return false事件处理函数将会继续执行,表单将提交2. return false,事件处理函数会取消事件,不再继续向下执行.比如 ...
-
http://www.jobui.com/mianshiti/it/java/6782/
1.运算符优先级问题,下面代码的结果是多少?(笔试) package test; public class Test {public static void main(String[] args) { ...
-
批处理for中字符串截取必须先把循环变量代替出来才行!!!
@echo off & setlocal enabledelayedexpansion set ifo=abc,def,ghi,jkl,mnopqrstuvwxyz0123456789 ech ...
-
Fastjson-fastjson中$ref对象重复引用问题:二
import java.util.ArrayList; import java.util.List; import com.alibaba.fastjson.JSON; import com.alib ...
-
Study 3 —— Python运算符
参考资料:http://www.runoob.com/python/python-operators.html#ysf2 定义变量: a = 10, b = 20 算术运算符: 运算符 描述 实例 ...
-
零基础学习hadoop到上手工作线路指导初级篇:hive及mapreduce(转)
零基础学习hadoop到上手工作线路指导初级篇:hive及mapreduce:http://www.aboutyun.com/thread-7567-1-1.html mapreduce学习目录总结 ...
-
J S 脚本语言 if() { if { } else { } } var a =100; switch { case ( ) break ; } 基础详解 , 最下面有例子
注释语法 注释语法// 多行注释/ JS输出语句 JS样式尽量靠最下面写 <script type="text/javascript">//嵌入JS开始代码 //ale ...
-
odoo tree视图 当页不弹窗显示方法
<xpath expr="//tree" position="attributes"> <attribute name='editable'& ...
-
1063 合并果子 2004年NOIP全国联赛普及组
题目描述 Description 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消耗的体力等 ...