一、多线程的初步理解
-
进程: 一个具有一定独立功能的程序关于某个数据集合的一次运行活动,可以理解成一个正在运行中的应用程序。
-
线程: 程序执行流的最小单元,线程是进程中的一个实体,程序的运行必须依靠一个线程才能运行,一个程序运行可以有单个线程, 也可以有多个线程。
-
同步: 只能在当前线程按先后顺序依次执行,不开启新线程。
-
异步: 可以在当前线程开启多个新线程执行,可不按顺序执行,开启新的线程。
-
并发: 线程执行可以同时多条线程一起进行执行,没有先后顺序,用于耗时较长的线程操作。
-
串行: 线程执行只能依次逐一先后有序的执行,前面的程序执行成后才能有后面的程序执行。
-
主线程:程序开始运行的时候,系统自动为我们开启一个新的线程,这个线程称为主线程
-
子线程:程序员手动开启的线程,程序运行结束后自动释放。
-
队列: 装载线程任务的队形结构,可以添加线程在同一个队列运行,任务运行在主线程还是子线程有队列决定。
二、多线程的分类及优缺点
1. pthread
优点:可以跨平台使用,基于纯C语言的面向对象,能够适用于多种操作系统, 可移植性强。
缺点:靠近底层实现,难以理解且使用难道大,线程的生命周期需要程序员自己管理,通常不使用。
举例:在view did load里面写如下代码 ( 注:需导入头文件 #import)
pthread_t pthread;新建一个
// 第一个参数: 线程指针
// 第二个参数: 线程的一些属性
// 第三个参数: 函数指针, 用于执行方法
// 第四个参数: 线程中的传值
pthread_create(&pthread, NULL, run, NULL);
方法实现 :
void *run(void *papa)
{
for (NSInteger i = 0; i < 100000; i ++) {
NSLog(@"%lu",i);
}
return NULL;
}
2.NSThread
-
优点:基于OC的面向对象编程,简单易用
-
缺点:线程的生命周期由程序员管理,偶尔使用
NSTHread *thread =[ [NSThread alloc] initWithTarget:self selector:@selector(run) objects:"thread"];
thread.name = "thread"
[thread start] // 开启线程
NSLog(@"%@",thread); // 线程打印
NSLog(@"%@",[NSThread mainThread]); // 当前应用程序的主线程
NSLog(@"%@",[NSThread currentThread]); // 当前线程
NSLog(@"%d",[NSThread isMainThread]); // 判断是否为主线程
// 快捷创建NSThread线程的方法
[NSThread detachNewThreadSelector:@selector(haoshicaozuo) toTarget:self withObject:@"123"];
[self performSelectorInBackground:@selector(haoshicaozuo) withObject:@"123"];
3.NSOperation
简介:NSOperation是个抽象类,我们一般不使用它,一般使用它的子类NSInvocationOperation和NSBlockOperation, 如果他们单独使用,则都是在主线程下执行,只有和队列放在一起才在子线程执行。
a.NSInvocationOperation
NSInvocationOperation *firstOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(firstRun) object:nil];
- (void) firstRun{
NSlog("第一个NSInvocation线程")
}
NSInvocationOperation *secondOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(secondRun) object:nil];
- (void) secondRun{
NSlog("第二个NSInvocation线程")
}
b.NSBlockOperation
NSBlockOperation *thirdOperation = [NSBlockOperation blockOperationWithBlock:^{
NSlog("block线程")
}
}];
// NSOperationQueue *queue = [NSOperationQueue mainQueue]; mainQueue代表主队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // alloc init 代表其他队列
NSOperationQueue的作⽤:NSOperation可以调⽤start⽅法来执⾏任务,但默认是同步执行的,
如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation
中的操作
添加操作到NSOperationQueue中,自动执行操作,自动开启线程
// 先加的先执行, 后加的后执行, 但是执行的时间不一定, 可能后执行的程序比先执行的先执行完
[queue addOperation:firstOperation]; // 将线程加入队列
[queue addOperation:secondOperation]; // 将线程加入队列
[queue addOperation:thirdOperation]; // 将线程加入队列
4. GCD
a.同步 + 主队列 (不具备开启线程的能力, 在当前的线程完成任务)
- (void)creatScyncSerial
{
// 创建串行队列
dispatch_queue_t queue = dispatch_queue_create("aaa.com.queue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
NSLog(@"1------%@",[NSThread currentThread]);
}); // dispatch_sync为同步
dispatch_sync(queue, ^{
NSLog(@"2------%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3------%@",[NSThread currentThread]);
});
}
注:NSlog出现不输出情况,因为同步串行出现相互等待的情况,程序无法运行
b.异步 + 串行队列(能开启线程, 任务一个一个执行)
- (void)creatAsyncSerial
{
dispatch_queue_t queue = dispatch_queue_create("aaa.com.queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"4--------%@",[NSThread currentThread]);
}); // dispatch_async 为异步
dispatch_async(queue, ^{
NSLog(@"5--------%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"6--------%@",[NSThread currentThread]);
});
}
c.同步 + 并发队列(不具备开启线程的能力, 无法并发)
- (void)creatSyncConcurrent
{
// 第一个参数: 队列的名字
// 第二个参数: 队列的类型
// 我们自己创建的并发队列
// dispatch_queue_t queue = dispatch_queue_create("sb.2b.com", DISPATCH_QUEUE_CONCURRENT);
// 创建一个并发队列
// 获得全局的并发队列
// 第一个参数为一个优先级: 默认的就行
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_sync(queue, ^{
NSLog(@"1-------%@",[NSThread currentThread]); });
dispatch_sync(queue, ^{
NSLog(@"2------%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3-------%@",[NSThread currentThread]);
});
}
d.异步 + 并发队列 (使用频率较高,具备开启子线程的能力, 并发执行)
- (void)creatAsncConcurrent
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSLog(@"1------%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2------%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3------%@",[NSThread currentThread]);
});
}
4.NSThreade的简单应用(saleTickets)
a.将线程和票数设置为属性
@property (nonatomic,strong)NSThread *firstThread; // A售票员
@property (nonatomic,strong)NSThread *secondThread; // B售票员
@property (nonatomic,strong)NSThread *thirdThread; // C售票员
@property (nonatomic,assign)NSInteger ticketCount; // 总票数
b.添加线程并开启
self.ticketCount = 100; // 总票数 设为100
self.firstThread = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.secondThread = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.thirdThread = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
触摸屏幕时开启子线程
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event
{
[self.firstThread start];
[self.secondThread start];
[self.thirdThread start];
}
卖票的方法
- (void)saleTicket
{
while (1) { // 设置1为死循环,未触发break时会一直运行卖票
// 线程锁 线程锁是唯一的, 只能有一把, 通常我们可以写上self, 加线程锁是防止三个线程同一时间卖票,当有一个线程开始卖票时,其他线程无法进行卖票。
@synchronized (self) {
// NSLog(@"%@",self);
// 先取出总票数
NSInteger count = self.ticketCount;
if (count > 0) {
self.ticketCount = count - 1;
[NSThread sleepForTimeInterval:0.1]; // 线程暂停休息
NSLog(@"%@, %lu",[NSThread currentThread], self.ticketCount);
}else{
NSLog(@"票卖完了");
break;
}
}
}