您的位置:首页 > 其它

多线程基础

2015-07-18 23:15 232 查看
1.多线程基础

1.1基本概念

1⃣ 进程

进程是指在系统中正在运行的一个应用程序

每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内。

2⃣线程

1个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程)线程是进程的基本执行单元,一个进程(程序)的所有任务都在线程中执行。

3⃣多线程

1个进程中可以开启多条线程,每条线程可以并发(同时)执行不同的任务,多线程技术可以提高程序的执行效率。

1.2多线程的原理

同一时间,CPU只能处理1条线程,只有1条线程在工作(执行,多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象

思考:如果线程非常非常多,会发生什么情况?

CPU会在N多线程之间调度,CPU会累死,消耗大量的CPU资源每条线程被调度执行的频次会降低(线程的执行效率降低)

1.3多线程的优缺点

优点:适当的提高程序的执行效率和资源利用率

缺点:开启线程需要占用一定的内存空间,如果开启大量的线程会占用大量的内存空间,降低程序的性能;线程开启的越多,cpu的地哦啊度线程的开销就越大;开启的线程多,会使程序的设计更加复杂,比如:程序间通信、多线程的数据共享……

1.4多线程在IOS开发中的应用

1.4.1 什么是主线程? 一个iOS程序运行后,默认会开启1条线程,称为“主线程”或“UI线程”

1.4.2 主线程的主要作用

① 显示\刷新UI界面

② 处理UI事件(比如点击事件、滚动事件、拖拽事件等)

*1.4.3主线程的使用注意

别将比较耗时的操作放到主线程中

耗时操作会卡住主线程,严重影响UI的流畅度,给用户一种“卡”的坏体验

1.5 代码

pthread

// MARK:- pthread演练

- (void)pthreadDemo {

/**
pthread 是属于 POSIX 多线程开发框架
 http://baike.baidu.com POSIX & socket

参数
1. 线程代号的地址 C语言中类型的结尾通常 _t/Ref,而且不需要使用 *
2. 线程的属性
3. 调用函数的指针
4. 传递给该函数的参数

返回值
- 如果是0,表示正确
- 如果是非0,表示错误码

void *(*)(void *)
返回值 (函数指针)(参数)

void * 和 OC 中的 id 是等价的
id(*)(id)

- 在 ARC 开发中,如果设计到和 C 语言中相同的数据类型进行转换时,需要使用 __bridge “桥接”
- 在 MRC 开发中,不需要桥接

在 OC 中,如果是 ARC 开发,编译器会在编译的时候,自动根据代码结构,添加 retain, release, autorelease
ARC 只负责 OC 部分的代码,不负责 C 的代码,如果 C 语言的框架出现 retain/create/copy 字样的函数,都需要release

关于桥接的添加,可以利用 Xcode 辅助实现!

*/
// 创建线程

pthread_t threadId;

NSString *str = @"Hello Pthread";

int result = pthread_create(&threadId, NULL, &demo, (__bridge void *)(str));

if (result == 0) {
NSLog(@"OK");
} else {
NSLog(@"error %d", result);
}


}

void *demo(void *param) {

NSString sss = (__bridge NSString )(param);

NSLog(@"%@, %@", [NSThread currentThread], sss);

return NULL;


}

NSThread创建方法

// MARK: NSThread 创建

- (void)threadDemo4 {

Person *p = [[Person alloc] init];

[p performSelectorInBackground:@selector(loadData) withObject:nil];


}

(void)threadDemo3 {

// 1

NSLog(@”1–%@”, [NSThread currentThread]);

// 是 NSObject 的一个分类方法,意味着所有的 NSObject 都可以使用此方法,在其他线程执行方法!

// 特点:没有thread字眼,一旦制定,就会立即在后台线程执行 selector 方法

// performSelectorInBackground 隐式的多线程方法

// 这种方法,在使用的时候更加灵活!

[self performSelectorInBackground:@selector(demo:) withObject:@”background”];

// 1

NSLog(@”2–%@”, [NSThread currentThread]);

}

(void)threadDemo2 {

// 1

NSLog(@”1–%@”, [NSThread currentThread]);

// detachNewThreadSelector 会理解在后台线程执行 selector 方法

// detach => 分离一个自线程执行 demo: 方法

[NSThread detachNewThreadSelector:@selector(demo:) toTarget:self withObject:@”Detach”];

// 1/2?

NSLog(@”2–%@”, [NSThread currentThread]);

}

(void)threadDemo1 {

NSLog(@”1——-“);

// 实例化/加载 => alloc(分配内存) / init(初始化)

NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(demo:) object:@”Thread”];

// 启动线程

[thread start];

// 1/2?

NSLog(@”2——- %@”, [NSThread currentThread]);

}

(void)demo:(id)obj {

for (int i = 0; i<2; i++) {

NSLog(@”%@ %@”, [NSThread currentThread], obj);

}

}

线程状态

(void)touchesBegan:(NSSet )touches withEvent:(UIEvent )event {

NSLog(@”走!!!”);

// 一定注意,不能杀死主线程!

// [NSThread exit];

[self threadDemo];

}

(void)threadDemo {

// 实例化线程对象(新建)

NSThread *t = [[NSThread alloc] initWithTarget:self selector:@selector(threadStatus) object:nil];

// 线程就绪(被添加到可调度线程池中)

[t start];

}

(void)threadStatus {

// 阻塞,当运行时满足某一个条件,会让线程”休眠”/锁

// 提示:sleep 方法是类方法,会直接休眠当前线程

NSLog(@”睡会”);

// 直接睡两秒

[NSThread sleepForTimeInterval:2.0];

for (int i = 0; i < 20; i++) {

if (i == 8) {

// 线程执行中,满足某一个条件时,再次休眠

NSLog(@”再睡会”);

// 睡到指定的日期,从现在开始过了多久

[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];

}

NSLog(@"%@ %d", [NSThread currentThread], i);

// 当线程满足某一个条件时,可以强行终止
if (i == 15) {
// 一旦强行终止线程,后续的所有代码都不会被执行
// 注意:在终止线程之前,应该注意释放之前分配的对象!
// 如果是 ARC 开发,需要注意,清理 C 语言框架创建的对象!否则会出现内存泄漏!
[NSThread exit];
}


}

NSLog(@”能来吗?”);

}

NSThread属性

/**

优先级只是保证 CPU 调度的可能性会高!

多线程的目的:将耗时的操作放在后台,不阻塞主线程和用户的交互!

个人建议,在开发的时候,不要修改优先级!优先级翻转!

多线程开发,有一个原则:尽量简单!

在多线程开发中,不要相信一次运行的结果!

*/

(void)threadDemo {

NSThread *t1 = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];

// 在大的商业项目中,通常希望程序崩溃的时候,能够获取到程序准确执行所在的线程!

t1.name = @”Thread A”;

// 优先级,是一个浮点数,从0~1.0,1.0表示优先级最高,默认优先级是0.5

// 优先级只是保证 CPU 调度的可能性会高!

t1.threadPriority = 0.1;

[t1 start];

//———————-

NSThread *t2 = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];

// 在大的商业项目中,通常希望程序崩溃的时候,能够获取到程序准确执行所在的线程!

t2.name = @”Thread B”;

// 优先级,是一个浮点数,从0~1.0,1.0表示优先级最高,默认优先级是0.5

t2.threadPriority = 1;

[t2 start];

}

(void)demo {

for (int i = 0; i < 10; i++) {

NSLog(@”%@ %d”, [NSThread currentThread], i);

}

// // 判断是否是主线程

// if (![NSThread isMainThread]) {

// // 模拟崩溃

// NSMutableArray *array = [NSMutableArray array];

// [array addObject:nil];

// }

}

nonatomic与 atomic

nonatomic: 非原子属性

atomic: 原子属性(线程安全),就是针对多线程设计的,是默认属性

多个线程写入属性时,保证同一时间只有一个线程能够执行写入操作

单(线程)写多(线程)读的一种多线程技术,同样有可能出现“脏数据”,重新读一下。

实际上,原子属性内部也有一把锁,自旋锁

自旋锁 & 互斥锁

-共同点

都能够保证同一时间,只有一条线程执行锁定范围的代码

-不同点

互斥锁:如果发现有其他线程正在执行锁定的代码,线程会进入休眠状态,等待其他线程执行完毕,打开锁之后,线程会被唤醒

自旋锁:如果发现有其他线程正在执行锁定的代码,线程会用死循环的方式,一直等待锁定代码执行完成!

自旋锁更适合执行非常短的代码!

无论什么锁,都是要付出代价的!

线程安全

在多个线程进行读写操作时,仍然能够保证数据正确!

UI 线程,共同约定:所有更新 UI 的操作都在主线程上执行!

原因:几乎所有的 UIKit 都不是线程安全的!”取舍”

日常开发中,使用锁的机会很少,多线程的目的,就是将耗时的操作放在后台!

线程间通讯

在主线程更新 UI

/**

performSelectorOnMainThread “线程间通讯”

在主线程执行的方法

传递给方法的参数

是否等待被调用方法执行完成,有可能也会等待调用方法的执行完成!几率极少!

*/

[self performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];

定时器

(void)viewDidLoad {

[super viewDidLoad];

/**

NSDefaultRunLoopMode - 时钟,网络事件;

NSRunLoopCommonModes - 用户交互;

*/

// 以下两句两种添加时钟的方法是等价的

NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(updateTimer) userInfo:nil repeats:YES];

// // 加入运行循环

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

// scheduledTimerWithTimeInterval 默认就是使用 NSDefaultRunLoopMode

// [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTimer) userInfo:nil repeats:YES];

}

(void)updateTimer {

static int num = 0;

// 如果时钟触发方法,执行非常耗时的操作!注意不能在时钟调用方法中,执行耗时的操作!

NSLog(@”睡会”);

[NSThread sleepForTimeInterval:1.0];

NSLog(@”%@ %d”, [NSThread currentThread], num++);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  多线程基础