iOS开发------多线程编程(1)

来源:互联网 发布:h5 js开发3d 编辑:程序博客网 时间:2024/04/30 22:06
////  ViewController.h//  UI22_MultiThreadProgranming////  Created by l on 15/10/6.//  Copyright (c) 2015年 lon. All rights reserved.//#import <UIKit/UIKit.h>@interface ViewController : UIViewController@property (strong, nonatomic) IBOutlet UIImageView *imageView;@end////  ViewController.m//  UI22_MultiThreadProgranming////  Created by l on 15/10/6.//  Copyright (c) 2015年 lon. All rights reserved.//#import "ViewController.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];#pragma mark-----------多线程概述-------------------------    /*  UI22 多线程编程     程序:由源代码生成的可执行应用。(例如:QQ.app)     进程:一个正在运行的程序可以看做一个进程。(例如:正在运行的QQ就是一个进程),进程拥有独立运行所需的全部资源。     线程:程序中独立运行的代码段。(例如:接收QQ消息的代码)     一个进程是由一或多个线程组成。进程只负责资源的调度和分配,线程才是程序真正的执行单元,负责代码的执行。     注意:iOS中关于UI的添加和刷新必须在主线程中操作。     主要知识点:     1.明确什么是多线程? 什么时候使用多线程? iOS使用多线程的几种方式.     具有多个线程的程序,称为多线程编程方式.     当有耗时, 或者消耗太多CPU的相关任务时,一般采用多线程编程,把耗时的任务让子线程去执行.     iOS中, 多线程的方式:     (1)NSThread     (2)NSOperationQueue     (3)NSObject     (4)GCD     2.线程之间的管理     */    /*    主线程   子线程    每个程序都至少有一个线程,负责调用main函数,这个线程就是主线程.    如果一个程序有多个线程,除去主线程,都是子线程.    线程和线程之间是独立运行的,互不干扰.    */    //练习1.模拟线程阻塞#pragma mark-------------- NSThread ---------------    //iOS中多线程实现的方式:    // 凡是我们开辟的线程都是子线程.    // 一. NSThread    //(1)创建线程 NSThread对象 (两种方式)    NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(blockThread:) object:nil];    //init创建方式,需要手动开启线程    [thread1 start];      //取消线程    [thread1 cancel];    //线程休眠//     [NSThread sleepForTimeInterval:3];//      NSLog(@"我睡了三秒");    //(2)类方法创建thread对象,不需要手动开启    [NSThread detachNewThreadSelector:@selector(blockThread:) toTarget:self withObject:nil];    //练习2.使用子线程进行图片下载    //http://image.photophoto.cn/nm-6/018/030/0180300244.jpg    [NSThread detachNewThreadSelector:@selector(imageDownload) toTarget:self withObject:nil];    /*    如何看所在的线程。    当前线程,是否是主线程?    NSLog(@"%d %@ %d",__LINE__,[NSThread currentThread], [NSThread isMainThread]);    */#pragma mark-------  NSOperation    NSOperationQueue ----------    //二.  操作, NSOperation(含子类)   操作对列, NSOperationQueue    //NSOperation 操作,两个子类为 NSInvocationOperation 和 NSBlockOperation, 封装了要执行的代码或者方法,和操作队列一起使用.    //把操作放到操作队列中,然后设置队里的并发个数,决定操作是并发执行,还是串行执行.    //并行:可以同时执行-> 同时有多个线程    //串行:一个执行完,才会执行另外一个 -> 同一时间只有一个线程    //1.创建操作对象    // NSInvocationOperation    NSInvocationOperation *invocationOp1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(printOne) object:nil];    // NSBlockOperation    NSBlockOperation *blockOp2 = [NSBlockOperation blockOperationWithBlock:^{        [self printTwo];    }];    //2.创建操作队列, 队列自动会开辟线程    NSOperationQueue *queue = [[NSOperationQueue alloc] init];    //设置队列的最大并行数 --> 同时执行的线程个数    queue.maxConcurrentOperationCount = 2;    //给操作添加依赖关系    [blockOp2 addDependency:invocationOp1]; //op1执行完毕才会执行op2    //3.添加操作//    [queue addOperation:invocationOp1];//    [queue addOperation:blockOp2];    //操作被添加到操作队列里面后就会自动执行#pragma mark----------- NSObject ----------------------    //三. NSObject () 一个多线程操作的分类    //object : 多线程分类里面的方法,在后面子线程中执行一个操作.    //本质是:帮我们快速创建了一个子线程,把相关操作放到了子线程中执行.//    [self performSelectorInBackground:@selector(blockThread:) withObject:nil];//    [self performSelectorOnMainThread:@selector(blockThread:) withObject:nil waitUntilDone:NO];#pragma mark----------- GCD --------------------------    //四. GCD 宏观中心分配 (队列) Grand Central Dispatch    //GCD 是函数式的多线程 , 分配具有特定功能的队列.    //比如:    // serialQueue 串行队列    //currentQueue 并行队列    //dispacth_once_t 只执行一次队列    //学习GCD,根据需求创建出不同的队列,实现出相应的逻辑功能,不用去考虑线程的创建.    // 线程之间通讯问题    /*     If your application has a graphical user interface, it is recommended that you receive user-related events and initiate interface updates from your application’s main thread. This approach helps avoid synchronization issues associated with handling user events and drawing window content. Some frameworks, such as Cocoa, generally require this behavior, but even for those that do not, keeping this behavior on the main thread has the advantage of simplifying the logic for managing your user interface.     如果你的应用有图像用户界面,建议你 在主线程中 接受用户相关事件和更新视图。此操作避免了 处理用户事件和绘制窗口内容的 同步问题,Cocoa框架,要求这么做,即使没有要求,这样在主线程中操作,简化了UI 管理逻辑 。     子线程也能刷新UI界面,但是还是子线程执行完毕后回到了主线程中才更新了UI。     */   }#pragma mark--------GCD-----//串行队列- (IBAction)serialQueue:(id)sender {    //1.串行队列    //(1)声明串行队列    dispatch_queue_t serialQueue = dispatch_queue_create("serial1", DISPATCH_QUEUE_SERIAL);    //系统提供的串行队列 ----- 主队列, 通过 dispatch_get_main_queue() 获取.    dispatch_queue_t mainQueue = dispatch_get_main_queue();    //(2)添加操作,往队列里面添加操作,只能添加block或者函数    /*  dispatch_async()    往队列中添加任务,任务会排队执行 */    /* dispatch_sync()      将任务添加到队列中,block不执行完,下面代码不会执行 */    /*        dispatch_sync:必须要等着block执行完毕之后才能执行Block外的内容。        dispatch_async:不用等着block执行完毕,就可以执行Block外的内容。     */    dispatch_async(serialQueue, ^{        NSLog(@"%@ %d", [NSThread currentThread], [NSThread isMainThread]);        NSLog(@"aaaaa");    });    dispatch_async(serialQueue, ^{        NSLog(@"%@ %d", [NSThread currentThread], [NSThread isMainThread]);        NSLog(@"bbbbb");    });    dispatch_async(serialQueue, ^{        NSLog(@"%@ %d", [NSThread currentThread], [NSThread isMainThread]);        NSLog(@"ccccc");    });}//并行队列- (IBAction)currentQueue:(id)sender {    //并行队列里面添加的任务,不会等待,但是也遵守fifo原则,只是当前一个任务执行时,后面会立即执行.    //(1)创建并行队列    dispatch_queue_t currentQueue = dispatch_queue_create("currentQueue", DISPATCH_QUEUE_CONCURRENT);    //系统提供的并行队列    dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);    //(2)添加任务    dispatch_async(currentQueue, ^{        NSLog(@"%@ %d", [NSThread currentThread], [NSThread isMainThread]);        NSLog(@"我出生了");    });    dispatch_async(currentQueue, ^{        NSLog(@"%@ %d", [NSThread currentThread], [NSThread isMainThread]);        NSLog(@"我长大了");    });    dispatch_async(currentQueue, ^{        NSLog(@"%@ %d", [NSThread currentThread], [NSThread isMainThread]);        NSLog(@"我结婚了");    });    dispatch_async(currentQueue, ^{        NSLog(@"%@ %d", [NSThread currentThread], [NSThread isMainThread]);        NSLog(@"我照片挂墙上了");    });}//分组提交方式- (IBAction)group:(id)sender {    //分组提交方式通常用来完成具有不同执行顺序的逻辑功能.    //比如: 一些任务需要并发执行,某一个任务需要最后执行.    //例如:多个网络解析    //创建并行队列    dispatch_queue_t queue2 = dispatch_get_global_queue(0, 0);    //创建分组    dispatch_group_t group = dispatch_group_create();    /* dispatch_group_async()   将任务添加到队列中,并添加分组标记 */    //分组提交方式,提交时加上分组标识    //并发执行    dispatch_group_async(group, queue2, ^{        NSLog(@"网络请求1");    });    dispatch_group_async(group, queue2, ^{        NSLog(@"网络请求2");    });    //最后执行操作    dispatch_group_notify(group, queue2, ^{        NSLog(@"网络请求1,2完成,进行数据相关的操作");    });}//barrier  障碍- (IBAction)barrier:(id)sender {    // 并行队列//    dispatch_queue_t queue2 = dispatch_get_global_queue(0, 0);    dispatch_queue_t queue2 = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);    //提交方式分为:同步提交和异步提交,    //同步提交 提交到队列里面的任务顺序与我们书写的代码先后顺序一致    //异步提交 可能不一致    //同步提交, 会卡线程, 异步不会.    //提交    dispatch_async(queue2, ^{        NSLog(@"aaaaaaaaaaa");    });    dispatch_async(queue2, ^{        NSLog(@"bbbbbbbbbbb");    });    /* dispatch_barrier_async() 将任务添加到队列中,此任务执行的时候,其他任务停止执行 */    //barrier 提交方式,执行依次方式提交的任务时,后面的任务等待,直到执行结束.    dispatch_barrier_async(queue2, ^{        for (int i = 0; i < 10; i++) {            NSLog(@"%d", i);        }    });    dispatch_async(queue2, ^{            NSLog(@"cccccccccc");    });}//apply 重复提交- (IBAction)apply:(id)sender {    //需要遍历或者需要重复执行的操作.    NSArray *array = @[@"网络连接1", @"网络连接2", @"网络连接3", @"网络连接4"];    //创建队列    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);    //apply提交方式    /* dispatch_apply()    往队列中添加任务,任务会重复执行n次 */    dispatch_apply(4, queue, ^(size_t i) {//        NSLog(@"当前执行第%d次", (int)i);        //模拟网络请求        NSLog(@"对%@进行网络请求", array[i]);    });}void sum(void *object) {//    NSArray *array = (__bridge NSArray *)object;//    //   return [array[0] intValue] + [array[1] intValue];    NSLog(@"%@", object);}- (IBAction)function:(id)sender {    //    dispatch_queue_t mainQueue = dispatch_get_main_queue();    //添加函数//    NSArray *array = @[@1, @2];//    dispatch_async_f(mainQueue, (__bridge void *)(array), sum);    /* dispatch_async_f()  将任务添加到队列中,任务是函数非block */    dispatch_async_f(mainQueue, @"acsdf", sum);}//延迟执行- (IBAction)after:(id)sender {    //1.创建队列//    dispatch_queue_t mainQueue = dispatch_get_main_queue();    //2.添加操作//    dispatch_after(dispatch_time_t when, dispatch_queue_t queue, <#^(void)block#>)    /*     参数1. dispatch_time 分配时间函数      1. 相对于何时 进行延迟操作     DISPATCH_TIME_NOW 当前时间     2. 延迟几秒执行  NSEC_PER_SEC 秒     参数2 添加的队列     参数3 执行的操作    */    /* dispatch_after() 往队列中添加任务,任务不但会排队,还会在延迟的时间点执行 */    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{        NSLog(@"5秒真男人");    });}#pragma mark-------operation----//one- (void)printOne{    NSLog(@"%d %@ %d", __LINE__, [NSThread currentThread], [NSThread isMainThread]);    NSLog(@"1111111");}//two- (void)printTwo{    NSLog(@"%d %@ %d", __LINE__, [NSThread currentThread], [NSThread isMainThread]);    NSLog(@"222222");}#pragma mark--------- 子线程进行图片下载 NSThread ------------ (void)imageDownload {    NSLog(@"%d %@ %d", __LINE__, [NSThread currentThread], [NSThread isMainThread]);    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://image.photophoto.cn/nm-6/018/030/0180300244.jpg"]];    //取到data之后,赋值给imageview的image    //更新UI的相关操作要放到主线程中去执行    /*     线程间通信分为两种:     主线程进入子线程(前面的方法都可以)     子线程回到主线程     */    //线程之间通讯问题,从子线程返回到主线程有两种方式    // 1. 使用 dispatch_get_main_queue()    // 2. 使用 nsobject  performSectorOnMainThread:    dispatch_async(dispatch_get_main_queue(), ^{        //UI操作在主线程中执行        _imageView.image = [UIImage imageWithData:data];        NSLog(@"%d %@ %d", __LINE__, [NSThread currentThread], [NSThread isMainThread]);    });    //2. object//    [self performSelectorOnMainThread:@selector(image) withObject:data waitUntilDone:NO];}- (void)image:(NSData *)data{    _imageView.image = [UIImage imageWithData:data];}#pragma mark----------- 模拟线程阻塞 -------------- (IBAction)blockThread:(id)sender {    for (int i = 0; i < 650000000; i++) {        NSLog(@"%d", i);    }    NSLog(@"线程被阻塞住了,没有办法继续执行");}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}@end//////////////////////////////////////////////////////////////  Singleton.h//  UI22_MultiThreadProgranming////  Created by l on 15/10/6.//  Copyright (c) 2015年 lon. All rights reserved.//#import <Foundation/Foundation.h>@interface Singleton : NSObject+ (Singleton *)sharedSingleton;@end////  Singleton.//  UI22_MultiThreadProgranming////  Created by l on 15/10/6.//  Copyright (c) 2015年 lon. All rights reserved.//#import "Singleton.h"static Singleton *singleton = nil;@implementation Singleton/* 线程互斥是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。 互斥无法限制访问者对资源的访问顺序,即访问是无序的。因此需要加上互斥锁来进行顺序访问,最具有代表性的就是买票系统! NSLock类能协助完成互斥操作。 */+ (Singleton *)sharedSingleton{    //1.dispatch_once    /* dispatch_once()  任务添加到队列中,但任务在程序运行过程中,只执行一次 */    //该队列里面的任务只执行一次    static dispatch_once_t queue;    dispatch_once(&queue, ^{        if (singleton == nil) {            singleton = [[Singleton alloc] init];        }    });    //2. lock 加锁 解锁方式    NSLock *lock = [[NSLock alloc] init];    //枷锁    [lock lock];    //线程安全相关的操作    if (singleton == nil) {        singleton = [[Singleton alloc] init];    }    //解锁    [lock unlock];    //3.同步锁    @synchronized(self){        if (singleton == nil) {            singleton = [[Singleton alloc] init];        }    }    return singleton;}/*- (NSInteger)retain{    return INT64_MAX;}+ (instancetype)alloc{    return  [SingleTon sharedSingleTon];}- (id)copy{    return  [SingleTon sharedSingleTon];}- (id)copyWithZone:(NSZone *)zone{    return  [SingleTon sharedSingleTon];}*/@end![storyborad](http://img.blog.csdn.net/20151006213428337)
0 0