一.进程的五态模型
二.线程是进程的基本执行单元,进程的所有任务都在线程中执行,每个进程都会至少有一个线程,称为主线程(UI线程)
三.为什么要用多线程
耗时操作比如网络请求,图片加载,文件处理,数据存储,任务执行,导致UI卡顿,体验不好
四.任务的执行方式
串行:多个任务按顺序执行,耗时为多个任务时间之和
并行:多个任务同时并发执行,耗时为最大任务耗时
五. 多线程的实现原理
对于单核操作系统,宏观上是并行,微观上是串行,操作系统会以操作片轮转调度的方式,来分配时间段,每个时间只允许一个线程执行
对于多核操作系统,是正真的并行
六.多线程的优缺点
优点:简化了编程模型
更加轻量级
提高了执行效率
提高资源利用率
缺点
多线程要解决的最大的问题就是资源共享和线程读写问题
增加程序设计复杂性
占用内存空间
增大CPU开销
七. 多线程的实现技术方案
pThread 基于C++语言,移植性好,用的少
NSThread 苹果封装后的,面向对象的
GCD 为多核提供的,用的Block封装了c,不需要关注生命周期
NSOperation 对gcd的封装
****************************
pThread
**********************************
#import
<pthread.h>
– (
IBAction
)pThread:(
UIButton
*)sender {
NSLog
(
@”
我在主线程中执行
”
);
//
创建线程
pthread_t
pthread;
pthread_create
(&pthread,
NULL
,
run
,
NULL
);
}
void
*run(
void
* data){
NSLog
(
@”
我在子线程中执行
”
);
for
(
int
i =
1
; i<
10
; i++) {
NSLog
(
@”%d”
,i);
sleep
(
1
);
}
return
NULL
;
}
****************************
NSThread
**********************************
#pragmamark – NSThread
– (
IBAction
)NSThread:(
id
)sender {
NSLog
(
@”
我在主线程中执行
–NSThread”
);
//1.
通过
alloc init
创建线程并执行
NSThread
* thread1 = [[
NSThread
alloc
]
initWithTarget
:
self
selector
:
@selector
(runThread1)
object
:
nil
];
[thread1
setName
:
@”NSThreadName1″
];
//
设置线程名
[thread1
setThreadPriority
:
0.2
];
//
设置线程执行前的延时时间
[thread1
start
];
NSLog
(
@”%@”
,[thread1
name
]);
NSThread
* thread2 = [[
NSThread
alloc
]
initWithTarget
:
self
selector
:
@selector
(runThread1)
object
:
nil
];
[thread2
setName
:
@”NSThreadName2″
];
[thread2
start
];
NSLog
(
@”%@”
,[thread2
name
]);
//2.
通过
detachNewThreadSelector
方式创建并执行线程
// [NSThread detachNewThreadSelector:@selector(runThread1) toTarget:selfwithObject:nil];
//3.
通过
performSelectorInBackground
方式创建并执行线程
// [self performSelectorInBackground:@selector(runThread1) withObject:nil];
}
-(
void
)runThread1{
NSLog
(
@”
我在子线程中执行
–NSThread”
);
for
(
int
i =
1
; i<=
10
; i++) {
NSLog
(
@”%d”
,i);
sleep
(
1
);
if
(i ==
10
) {
[
self
performSelectorOnMainThread
:
@selector
(runMainThread)
withObject
:
nil
waitUntilDone
:
YES
];
}
}
}
-(
void
)runMainThread{
NSLog
(
@”
回到主线程执行!!!
”
);
}
****************************
GCD
**********************************
#pragma mark — 1 基本gcd
-(
IBAction
)gcd_1{
LOG
dispatch_async
(
dispatch_get_global_queue
(
DISPATCH_QUEUE_PRIORITY_DEFAULT
,
0
), ^(
void
){
//
开辟子线程执行耗时任务
NSLog
(
@”GCD
子线程
”
);
LOG
[
NSThread
sleepForTimeInterval
:
2
];
dispatch_async
(
dispatch_get_main_queue
(),^(
void
){
//
返回主线程
NSLog
(
@”
回到主线程执行!!!
”
);
LOG
});
});
}
#pragma mark — 2 在定义优先级的情况下,会按照优先级去执行;在不定义优先级的情况下,默认多个gcd是全局并发执行
-(
IBAction
)gcd_2{
LOG
//DISPATCH_QUEUE_PRIORITY_HIGH
优先级
dispatch_async
(
dispatch_get_global_queue
(
DISPATCH_QUEUE_PRIORITY_LOW
,
0
), ^{
NSLog
(
@”task 1″
);
LOG
});
dispatch_async
(
dispatch_get_global_queue
(
DISPATCH_QUEUE_PRIORITY_HIGH
,
0
), ^{
NSLog
(
@”task 2″
);
LOG
});
dispatch_async
(
dispatch_get_global_queue
(
DISPATCH_QUEUE_PRIORITY_DEFAULT
,
0
), ^{
NSLog
(
@”task 3″
);
LOG
});
}
#pragma mark — 3 自定义队列,只开辟了一条线程,会按照顺序执行,可以通过修改参数定义是并行还是串行
-(
IBAction
)gcd_3{
//dispatch_queue_create(“com.test.gcd.queue”,NULL);//
参数为
NULL
说明是串行队列
//dispatch_queue_create(“com.test.gcd.queue”,DISPATCH_QUEUE_CONCURRENT);//
参数为
DISPATCH_QUEUE_CONCURRENT
说明是并行队列
dispatch_queue_t
queue=
dispatch_queue_create
(
“com.test.gcd.queue”
,
NULL
);
dispatch_async
(queue,^{
NSLog
(
@”
自定义子线程
1″
);
LOG
[
NSThread
sleepForTimeInterval
:
2
];
NSLog
(
@”
结束自定义子线程
1″
);
});
dispatch_async
(queue,^{
NSLog
(
@”
自定义子线程
2″
);
LOG
[
NSThread
sleepForTimeInterval
:
2
];
NSLog
(
@”
结束自定义子线程
3″
);
});
dispatch_async
(queue,^{
NSLog
(
@”
自定义子线程
3″
);
LOG
[
NSThread
sleepForTimeInterval
:
2
];
NSLog
(
@”
结束自定义子线程
3″
);
});
}
#pragma mark — 4 多个线程结束后的统一回调处理 – group
-(
IBAction
)gcd_4{
dispatch_queue_t
queue =
dispatch_queue_create
(
“com.test.gcd.queue”
,
DISPATCH_QUEUE_CONCURRENT
);
dispatch_group_t
group =
dispatch_group_create
();
dispatch_group_async
(group, queue, ^{
NSLog
(
@”start tast 1″
);
LOG
[
NSThread
sleepForTimeInterval
:
2
];
NSLog
(
@”end tast 1″
);
});
dispatch_group_async
(group, queue, ^{
NSLog
(
@”start tast 2″
);
LOG
[
NSThread
sleepForTimeInterval
:
2
];
NSLog
(
@”end tast 2″
);
});
dispatch_group_async
(group, queue, ^{
NSLog
(
@”start tast 3″
);
LOG
[
NSThread
sleepForTimeInterval
:
2
];
NSLog
(
@”end tast 3″
);
});
dispatch_group_notify
(group, queue, ^{
NSLog
(
@”all task over”
);
LOG
dispatch_sync
(
dispatch_get_main_queue
(),^(
void
){
NSLog
(
@”
回到主线程刷新
UI”
);
LOG
});
});
}
****************************
GCD应用
**********************************
#pragma mark – 单例 – 通过dispatch_once方法,只执行一次
– (
IBAction
)single:(
id
)sender {
[
TestSingle
instance
];
}
#pragma mark – 延迟执行
– (
IBAction
)delayRun:(
id
)sender {
NSLog
(
@”——begin—–”
);
dispatch_after
(
dispatch_time
(
DISPATCH_TIME_NOW
, (
int64_t
)(
2
*
NSEC_PER_SEC
)),
dispatch_get_main_queue
(), ^{
NSLog
(
@”—–
延迟执行
—–”
);
});
}
****************************
NSOperation
**********************************
//NSOperation 对gcd的封装
//1 有两种使用方式
// (1)NSInvocationOperation和NSBlockOperation
// (2)自定义类继承NSOperation
//2 相关概念
//(1).NSOperationQueue 队列,线程池
//a.addOperation
//b.setMaxConcurrentOperationCount
//(2).状态
//ready, cancelled , executing ,finished , asynchronous
//(3).依赖 addDependency
#pragmamark – NSInvocationOperation
-(
IBAction
)NSOperation_1:(
id
)sender{
LOG
//1NSInvocationOperation
是非并发的,也就是说同步执行的,会阻塞当前的线程
NSInvocationOperation
* invocationOperation = [[
NSInvocationOperation
alloc
]
initWithTarget
:
self
selector
:
@selector
(invocationOperation)
object
:
nil
];
[invocationOperation
start
];
NSLog
(
@”end”
);
}
-(
void
)invocationOperation{
LOG
for
(
int
i =
0
; i<
3
; i++) {
NSLog
(
@”invocationOperation %d”
,i);
[
NSThread
sleepForTimeInterval
:
1
];
}
}
#pragmamark – NSBlockOperation
-(
IBAction
)NSOperation_2:(
id
)sender{
LOG
//2NSBlockOperation
同步执行
NSBlockOperation
* blockOpertion = [
NSBlockOperation
blockOperationWithBlock
:^{
LOG
for
(
int
i =
0
; i<
3
; i++) {
NSLog
(
@”invocationOperation %d”
,i);
[
NSThread
sleepForTimeInterval
:
1
];
}
}];
[blockOpertion
start
];
}
#pragma mark – 异步方式实现
-(
IBAction
)NSOperation_3:(
id
)sender{
LOG
//
以上两种都是同步的,真正使用中异步用的多,使用
NSOperation
和
NSOperationQueue
结合的方式实现异步
NSBlockOperation
* blockOpertion = [
NSBlockOperation
blockOperationWithBlock
:^{
LOG
for
(
int
i =
0
; i<
3
; i++) {
NSLog
(
@”invocationOperation %d”
,i);
[
NSThread
sleepForTimeInterval
:
1
];
}
}];
if
(!
self
.
operationQueue
) {
self
.
operationQueue
= [[
NSOperationQueue
alloc
]
init
];
}
[
self
.
operationQueue
addOperation
:blockOpertion];
NSLog
(
@”end”
);
}
#pragma mark – 自定义NSOperation
– (
IBAction
)customOperation:(
id
)sender {
if
(!
self
.
operationQueue
) {
self
.
operationQueue
= [[
NSOperationQueue
alloc
]
init
];
}
//
设置并发最大线程数,同一时刻允许执行几条线程
[
self
.
operationQueue
setMaxConcurrentOperationCount
:
4
];
CustomOperation
* customOpar1 = [[
CustomOperation
alloc
]
initWithOperationName
:
@”customOpar1″
];
[
self
.
operationQueue
addOperation
:customOpar1];
CustomOperation
* customOpar2 = [[
CustomOperation
alloc
]
initWithOperationName
:
@”customOpar2″
];
[
self
.
operationQueue
addOperation
:customOpar2];
CustomOperation
* customOpar3 = [[
CustomOperation
alloc
]
initWithOperationName
:
@”customOpar3″
];
[
self
.
operationQueue
addOperation
:customOpar3];
CustomOperation
* customOpar4 = [[
CustomOperation
alloc
]
initWithOperationName
:
@”customOpar4″
];
[
self
.
operationQueue
addOperation
:customOpar4];
//
依赖
//
前者依赖于后者
不能造成循环依赖,结果是一个个执行,
2314
一次执行
[customOpar4
addDependency
:customOpar1];
[customOpar1
addDependency
:customOpar3];
[customOpar3
addDependency
:customOpar2];
NSLog
(
@”end”
);
// 运行结果:
// end
// customOpar1 , 0
// customOpar1 , 1
// customOpar1 , 2 说明:异步执行
// 运行结果:
// end
// customOpar3 , 0
// customOpar4 , 0
// customOpar2 , 0
// customOpar1 , 0
// customOpar3 , 1
// customOpar4 , 1
// customOpar1 , 1
// customOpar2 , 1
// customOpar4 , 2
// customOpar1 , 2
// customOpar2 , 2
// customOpar3 , 2 说明:并发执行
}
********************
多线程资源争夺问题解决
–
加锁
****************************
#import
<Foundation/Foundation.h>
@interface
TicketManager :
NSObject
-(
void
)startToSale;
@end
#import
“TicketManager.h”
#define Total
50
@interface
TicketManager
()
@property
int
tickets;
//
剩余票数
@property
int
saleCount;
//
卖出票数
@property
(
strong
,
nonatomic
)
NSThread
* threadBJ;
@property
(
strong
,
nonatomic
)
NSThread
* threadSH;
@property
(
strong
,
nonatomic
)
NSThread
* threadXA;
@property
(
strong
,
nonatomic
)
NSCondition
* ticketCondition;
//
第二种加锁方式
@end
@implementation
TicketManager
-(
instancetype
)init{
if
(
self
= [
super
init
]) {
self
.
tickets
=
Total
;
self
.
ticketCondition
= [[
NSCondition
alloc
]
init
];
//
初始化锁
self
.
threadBJ
= [[
NSThread
alloc
]
initWithTarget
:
self
selector
:
@selector
(sale)
object
:
nil
];
[
self
.
threadBJ
setName
:
@”BJ_thread”
];
self
.
threadSH
= [[
NSThread
alloc
]
initWithTarget
:
self
selector
:
@selector
(sale)
object
:
nil
];
[
self
.
threadSH
setName
:
@”SH_thread”
];
self
.
threadXA
= [[
NSThread
alloc
]
initWithTarget
:
self
selector
:
@selector
(sale)
object
:
nil
];
[
self
.
threadXA
setName
:
@”XA_thread”
];
}
return
self
;
}
-(
void
)sale{
while
(
true
) {
//
第一种加锁方式
// @synchronized(self) {
//
第二种加锁方式
[
self
.
ticketCondition
lock
];
//self.tickets > 0
说明还有票可以卖
if
(
self
.
tickets
>
0
) {
[
NSThread
sleepForTimeInterval
:
0.2
];
self
.
tickets
–;
self
.
saleCount
=
Total
–
self
.
tickets
;
NSLog
(
@”
当前线程
:%@ ,
剩余票数
:%d ,
售出票数
:%d”
,[
NSThread
currentThread
].
name
,
self
.
tickets
,
self
.
saleCount
);
}
//
第二种加锁方式
[
self
.
ticketCondition
unlock
];
}
// }
}
-(
void
)startToSale{
[
self
.
threadBJ
start
];
[
self
.
threadSH
start
];
[
self
.
threadXA
start
];
}
@end
调用:
-(
IBAction
)buyTicket:(
id
)sender{
//
多线程要解决资源共享问题,加锁
TicketManager
* manager = [[
TicketManager
alloc
]
init
];
[manager
startToSale
];
}