一:基本概念

1:进程:正在运行的程序为进程。

2:线程:每个进程要想执行任务必须得有线程,进程中任务的执行都是在线程中。

3:线程的串行:一条线程里任务的执行都是串行的,假如有一个进程开辟了一条线程,此条线程里有ABC三个任务,则ABC三个任务的执行是串行的,ABC三个任务按顺序一个个执行

4:多线程:一个进程可以开辟多条线程去并行(同时)去执行任务,假如有ABC三个任务,则此进程会开辟多条线程去并发执行ABC三个任务,可以提高运行效率

5:线程的原理:同一时间,cpu只能处理一条线程,而且也只有一条线程在工作,多线程的并发执行,也就是cpu在多条线程间爱会切换调度。进程一启动,就默认创建了一条线程为主线程大约为1M,所创建的子线程大约为512KB。

6:多线程的缺点:1:大量开线程,会大量占用cpu资源,cpu在调度线程上的开销也就越大 2:大量开线程,会使每条线程的执行效率降低,程序的性能降低,对于移动开发来说,适当开辟线程,大量开线程会使程序的想能降低

7:ios开发中多线程的应用:程序一启动就默认会开辟一条线程,成为主线程,也就是UI线程,主线程主要负责,刷新和显示UI,处理按钮的点击事件,表格的滚动拖拽事件,尽量避免把耗时的操作放在主线程。凡在主线程执行的任务都是串行的,按照顺序一个个执行,若把耗时的操作放在主线程,则会卡主主线程,影响主线程的其他操作,造成很差的用户体验。正确的做法是:将比较耗时的操作放在子线程中去执行,不要影响主线程的其他操作。

8:获得当前线程:[NSThread currentThread]; 获得主线程:[NSThread mainThread];

9:ios中的多线程方案:1:Pthread:跨平台,适用于各个系统,线程的生命周期由程序员去管理。 2:NSThread 3:GCD:由系统自动去管理线程的声明周期   4:NSOperation:基于GCD封装,也是右系统去管理线程的生命周期。

二:线程的安全:

1:线程安全:当同一块资源被多条线程同时访问的时候,会涉及到线程安全的问题,例如卖票,银行取钱问题。解决方法:加互斥锁

@synchronized(self) {被锁住的代码 }(加锁是很耗性能的,当只有多条线程访问统一资源的时候,才考虑去加互斥锁)。加锁的工作原理是:加互斥锁后,同一时间只许可一条线程访问该资源,其他线程无法访问。当某条线程访问该资源时,会加一把锁,被锁住的代码执行完毕后,锁会被打开,下个线程此时才可以访问该资源,注意:锁对象必须是唯一的,否则多条线程依然可以访问该资源。锁对象一般用self,因为在控制器中,控制器对象就是唯一的,保证了锁对象的唯一性。

2:线程同步:加锁用的就是线程同步技术,多条线程同一条线程上按顺序依次执行 线程异步:多条线程异步去执行

3:原子与非原子属性:atomic是原子属性,默认是线程安全的,在执行setter方法赋值的时候,会加一把互斥锁,等待赋值结束后,所才被打开,防止了多条线程同时访问造成的线程安全问题。虽然是线程安全的,但是加锁消耗了大量的资源 。nonatomic:非原子属性,线程不安全的,没有加锁,因为在实际移动开发中,调用setter方法大部分都是在主线程,所以不涉及多条线程同时访问的问题。若涉及了多线程同时访问该资源,可以加一把互斥锁,还可以用atomic原子属性去修饰

三:GDC

1:GCD有两个核心的概念:1:队列 2:任务,其中队列是用来存放任务,GCD的使用:创建任务直接将任务放到队列里,GCD会自动将任务从队列里取出,按照FIFO原则(先进先出,后进后出,栈是现进后出)取出任务,放到相应的线程中去执行任务。

2:GCD有两个常用的函数用来执行任务:1:同步函数: dispatch_sync

dispatch_sync(queue, ^{

});

2:异步函数:dispatch_async

dispatch_async(queue, ^{

});

其中queue为队列,block为任务。其中同步函数:在当前线程中按顺序串行执行任务,不具备开启线程的能力 异步函数:在新的线程中执行,具备开启新线程的能力

3:GCD两大队列:1:串行队列:队列中的任务按顺序执行,一个任务执行完毕才会去执行下一个任务  2:并发队列:可以并发同时执行多个任务,并发队列只有在异步函数 dispatch_async中才能起到并发执行的作用

总结:1:同步和异步主要影响能不能开启新的线程 2:串行队列和并发队列主要影响任务执行的方式:串行:按顺序依次执行,并发队列:多个任务同时执行 3:看一条线程,先看最外层是同步还是异步,若是同步,不能开启新的线程,只在当前的线程中执行,若是异步,则具备开启新线程的能力,可以在新县城中执行 再看内层:若是串行队列:则任务按顺序执行 若是并发队列:则可以并发同时还行任务,但只有在异步函数中才会并发执行任务。

4:队列的创建:

1:dispatch_queue_t queue = dispatch_queue_create(a,b);a参数为队列名称,C语言字符串,用"",b参数为队列,串行队列:DISPATCH_QUEUE_SERIAL,也可以这么创建串行队列

dispatch_queue_t queue = dispatch_queue_create("com.520it.queue", NULL);

并发队列:DISPATCH_QUEUE_SERIAL NULL  注意:1:异步并发队列有三个任务,则并不会一定开启三条线程,开启线程的个数是由GCD内部去决定的。2:任务添加到队列后,会按FIFO原则将任务取出,并发执行,也就是三个任务的执行先后顺序是不确定的

2:并发队列的创建:1:可以获取到全局并发队列:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);第一个参数为队列优先级,默认为DEFAULT,也可以传0,第二个参数暂时用不到传0就可以,当涉及多条线程需要设定优先级时,可以设置第一个参数 2:也可以手动去创建并发队列dispatch_queue_create(a,b)

5:GCD的各种队列:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
} - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self syncMain];
} /**
* 同步函数 + 主队列:只打印begin,是因为同步函数放在串行队列中会卡主当前线程,造成死锁。同步函数不开启线程在当前线程中执行,且立即执行,而主线程的任务end要先执行完再去执行同步函数中任务,而同步函数又要立即执行,所以会造成死锁
*/
- (void)syncMain
{
NSLog(@"syncMain ----- begin"); // 1.获得主队列
dispatch_queue_t queue = dispatch_get_main_queue(); // 2.将任务加入队列
dispatch_sync(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
}); NSLog(@"syncMain ----- end");
} /**
* 异步函数 + 主队列:只在主线程中执行任务。无论同步还是异步,只要将任务放到追队列里,任务就会在主线程中执行,且是串行执行任务,主队列是一种特殊的串行队列。因为123任务是后添加到主队列里的任务,所以先执行完 start 和 end 在执行 1,2,3
*/
- (void)asyncMain
{ NSLog(@"syncConcurrent--------start");
// 1.获得主队列
dispatch_queue_t queue = dispatch_get_main_queue(); // 2.将任务加入队列
dispatch_async(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
});
NSLog(@"syncConcurrent--------end");
} /**
* 同步函数 + 串行队列:同步不会开启新的线程,在当前线程串行执行任务,且立即执行任务。任务是串行的,执行完一个任务,再执行下一个任务。打印顺序:start 1,2,3 end
*/
- (void)syncSerial
{ NSLog(@"syncConcurrent--------start");
// 1.创建串行队列
dispatch_queue_t queue = dispatch_queue_create("com.520it.queue", DISPATCH_QUEUE_SERIAL); // 2.将任务加入队列
dispatch_sync(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
}); NSLog(@"syncConcurrent--------end");
} /**
* 异步函数 + 串行队列:异步函数会开启新的线程,但是任务是串行的,任务按顺序执行执行完一个任务,再执行下一个任务。所以只开启一条线程(在一条线程中任务是按照顺序一个接一个执行)。打印顺序:statrt end 1 2 3。相当于把asyncSerial任务放到了主队列中执行,任务则在主线程中执行,又将任务123放到了串行队列中执行,所以先执行完主线程的任务,在执行串行队列的任务,所以先打印start end 再按照顺序依次执行任务1,2,3
*/
- (void)asyncSerial { NSLog(@"syncConcurrent--------start");
// 1.创建串行队列
dispatch_queue_t queue = dispatch_queue_create("com.520it.queue", DISPATCH_QUEUE_SERIAL);
// dispatch_queue_t queue = dispatch_queue_create("com.520it.queue", NULL); // 2.将任务加入队列
dispatch_async(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
}); NSLog(@"syncConcurrent--------end");
} /**
* 同步函数 + 并发队列:不会开启新的线程,在当前线程中串行执行任务且立即执行任务,因为并发队列只有在异步函数中才会起作用,打印顺序:start 1,2,3,end
*/
- (void)syncConcurrent
{
NSLog(@"syncConcurrent--------start");
// 1.获得全局的并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ); // 2.将任务加入队列
dispatch_sync(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
}); NSLog(@"syncConcurrent--------end");
} /**
* 异步函数 + 并发队列:1:可以同时开启多条线程并发同时执行任务,开启线程的个数不确定,并且并发队列只有在异步函数下才有效 2:代码执行的顺序是先打印 satrt 在打印 end 最后再打印子线程中的内容,先执行主线程中的任务,在执行异步线程的任务,123任务执行完成的先后顺序是不确定的。原因是:相当于把asyncConcurrent任务放到了主队列里,在主线程执行,任务是按照FIFO原则从队列中取出,所以先执行完start后,分别将任务123添加到了全局并发队列里,123任务是后添加到队列中的,所以先执行完主队列任务,再异步并发执行子线程中的任务。
*/
- (void)asyncConcurrent
{
// 1.创建一个并发队列
// label : 相当于队列的名字
// dispatch_queue_t queue = dispatch_queue_create("com.520it.queue", DISPATCH_QUEUE_CONCURRENT); NSLog(@"asyncConcurrent--------start"); // 1.获得全局的并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ); // 2.将任务加入队列
dispatch_async(queue, ^{
for (NSInteger i = ; i<; i++) {
NSLog(@"1-----%@", [NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (NSInteger i = ; i<; i++) {
NSLog(@"2-----%@", [NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (NSInteger i = ; i<; i++) {
NSLog(@"3-----%@", [NSThread currentThread]);
}
}); NSLog(@"asyncConcurrent--------end"); } @end

6:GCD中的线程间通信

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView; @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
} - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"---------------------------------------1");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ), ^{
NSLog(@"---------------------------------------3");
// 图片的网络路径
NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"]; // 加载图片
NSData *data = [NSData dataWithContentsOfURL:url]; // 生成图片
UIImage *image = [UIImage imageWithData:data]; // 回到主线程
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
NSLog(@"-------------------------------------5");
}); NSLog(@"---------------------------------------4"); }); NSLog(@"---------------------------------------2");
} @end

打印顺序:1,2,3,4,5,先执行主线程中的任务,1,2 主线程中的任务执行完毕后再去异步执行子线程中的任务,先执行完子线程中的任务3,4 后,再回到主线程执行任务5。原因:相当于把touchBegan任务放到了主队列里,任务在主线程中执行,子线程中的任务是后面添加到并发队列里的,所以先回执行完主线程中的任务1,2 当执行完毕后再去执行子线程中的任务,在子线程中的任务5是后面加入到主队列的,所以先回执行完子线程中的任务3,4,再回到主线程里执行任务5

6:GCD的其他函数

#import "ViewController.h"
#import "XMGPerson.h" @interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
/** 图片1 */
@property (nonatomic, strong) UIImage *image1;
/** 图片2 */
@property (nonatomic, strong) UIImage *image2;
@end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad]; XMGPerson *person1 = [[XMGPerson alloc] init];
XMGPerson *person2 = [[XMGPerson alloc] init];
XMGPerson *person3 = [[XMGPerson alloc] init];
XMGPerson *person4 = [[XMGPerson alloc] init]; // XMGPerson *p1 = [[XMGPerson alloc] init];
// NSLog(@"%@", p1.books);
//
// XMGPerson *p2 = [[XMGPerson alloc] init];
// NSLog(@"%@", p2.books); } void download(void * data)
{ } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>);
// dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// dispatch_async_f(queue, NULL, download); // [self group];
[self barrier];
}
/**
* 群组:1:群组中的任务是并发执行的,会等群组中的任务都执行完毕后,会调用 dispatch_group_notify,在并发队列中完成绘图操作,在主线程中去显示图片。1:首先创建群组: dispatch_group_t group = dispatch_group_create(); 2:将任务放到并发队列中,将队列放到群组中,12任务执行完不确定 3:都执行完调用dispatch_group_async,将耗时的绘图操作还放在异步线程,绘图完毕后,回到主线程显示UI
*/
- (void)group
{ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
// 创建一个队列组
dispatch_group_t group = dispatch_group_create(); // 1.下载图片1
dispatch_group_async(group, queue, ^{
// 图片的网络路径
NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"]; // 加载图片
NSData *data = [NSData dataWithContentsOfURL:url]; // 生成图片
self.image1 = [UIImage imageWithData:data];
}); // 2.下载图片2
dispatch_group_async(group, queue, ^{
// 图片的网络路径
NSURL *url = [NSURL URLWithString:@"http://pic38.nipic.com/20140228/5571398_215900721128_2.jpg"]; // 加载图片
NSData *data = [NSData dataWithContentsOfURL:url]; // 生成图片
self.image2 = [UIImage imageWithData:data];
}); // 3.将图片1、图片2合成一张新的图片
dispatch_group_notify(group, queue, ^{
// 开启新的图形上下文
UIGraphicsBeginImageContext(CGSizeMake(, )); // 绘制图片
[self.image1 drawInRect:CGRectMake(, , , )];
[self.image2 drawInRect:CGRectMake(, , , )]; // 取得上下文中的图片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); // 结束上下文
UIGraphicsEndImageContext(); // 回到主线程显示图片
dispatch_async(dispatch_get_main_queue(), ^{
// 4.将新图片显示出来
self.imageView.image = image;
});
});
} /**
* 快速迭代:dispatch_apply(subpaths.count, queue, ^(size_t index):快速迭代函数:第一个参数为迭代对象的个数,第二个参数为队列,index为返回的索引,快速迭代,并发执行,提高迭代效率
*/
- (void)apply
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
NSString *from = @"/Users/xiaomage/Desktop/From";
NSString *to = @"/Users/xiaomage/Desktop/To"; NSFileManager *mgr = [NSFileManager defaultManager];
NSArray *subpaths = [mgr subpathsAtPath:from]; dispatch_apply(subpaths.count, queue, ^(size_t index) {
NSString *subpath = subpaths[index];
NSString *fromFullpath = [from stringByAppendingPathComponent:subpath];
NSString *toFullpath = [to stringByAppendingPathComponent:subpath];
// 剪切
[mgr moveItemAtPath:fromFullpath toPath:toFullpath error:nil]; NSLog(@"%@---%@", [NSThread currentThread], subpath);
});
} /**
* 传统文件剪切
*/
- (void)moveFile
{
NSString *from = @"/Users/xiaomage/Desktop/From";
NSString *to = @"/Users/xiaomage/Desktop/To"; NSFileManager *mgr = [NSFileManager defaultManager];
//此方法获得的是from路径下的所有文件路径,包括子文件夹下的文件路径
NSArray *subpaths = [mgr subpathsAtPath:from]; for (NSString *subpath in subpaths) {
NSString *fromFullpath = [from stringByAppendingPathComponent:subpath];
NSString *toFullpath = [to stringByAppendingPathComponent:subpath];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ), ^{
// 将文件从一个文件夹移动到另一个文件夹:是个耗时的操作,座椅在子线程中执行
[mgr moveItemAtPath:fromFullpath toPath:toFullpath error:nil];
});
}
}
/**
* 一次性函数:在整个项目中只执行一次
*/
- (void)once
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"------run");
});
} /**
* 延迟执行:GCD延迟函数:dispatch_after所传的队列不同,就在不同的队列中执行延迟函数,延迟的方法有以下三种
*/
- (void)delay
{
NSLog(@"touchesBegan-----");
// [self performSelector:@selector(run) withObject:nil afterDelay:2.0]; // dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// NSLog(@"run-----");
// }); [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO];
} - (void)run
{
NSLog(@"run-----");
} /**
* dispatch_barrier_async函数:能保证先12任务先执行完,在执行dispatch_barrier_async中的任务,最后在执行34任务,要想此函数起作用,queue不能是全局并发队列,因为queue是并发队列,所以12,34执行完的先后顺序不确定,但是能保证先执行12,在执行dispatch_barrier_async函数任务,最后执行34
*/
- (void)barrier
{
dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{
NSLog(@"----1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----2-----%@", [NSThread currentThread]);
}); dispatch_barrier_async(queue, ^{
NSLog(@"----barrier-----%@", [NSThread currentThread]);
}); dispatch_async(queue, ^{
NSLog(@"----3-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----4-----%@", [NSThread currentThread]);
});
} @end

7:GCD下完整的单例模式:GCD模式下的单例保证了线程的安全,dispatch_once是线程安全的,防止同一时间多条线程初始化同一个变量

#import "XMGPerson.h"

@interface XMGPerson() <NSCopying>

@end

@implementation XMGPerson

/**
* 模拟三种情况得到单例对象:
1:alloc创建对象 2:通过对象copy得到一个新对象 3:直接调用sharedPerson得到一个新对象
2:1:先用static定义一个下划线的成员变量 2:alloc方法内部会调用allocWithZone方法,用dispatch_once函数调用父类[super allocWithZone:zone]去开辟空间 3:当在类中实现copyWithZone方法时,需要类去遵守NSCopying协议,直接将成员变量返回,是因为调用copy之前该对象已经被初始化了
*/
static XMGPerson *_person; + (instancetype)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_person = [super allocWithZone:zone];
});
return _person;
} + (instancetype)sharedPerson
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_person = [[self alloc] init];
});
return _person;
} - (id)copyWithZone:(NSZone *)zone
{
return _person;
}
@end

8:单例的宏定义:其中的\表示下一行也属于宏定义

// .h文件
#define XMGSingletonH(name) + (instancetype)shared##name; // .m文件
#define XMGSingletonM(name) \
static id _instance; \
\
+ (instancetype)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [super allocWithZone:zone]; \
}); \
return _instance; \
} \
\
+ (instancetype)shared##name \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [[self alloc] init]; \
}); \
return _instance; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return _instance; \
}

9:非GCD模式下的单例:加锁的目的是保证线程安全,防止同一时间多条线程访问初始化同一个变量

#import "XMGPerson.h"

@interface XMGPerson()

@end

@implementation XMGPerson

static id _instance;

+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
@synchronized(self) {
if (_instance == nil) {
_instance = [super allocWithZone:zone];
}
}
return _instance;
} + (instancetype)sharedInstance
{
@synchronized(self) {
if (_instance == nil) {
_instance = [[self alloc] init];
}
}
return _instance;
} - (id)copyWithZone:(NSZone *)zone
{
return _instance;
}
@end

ios开发之多线程---GCD的更多相关文章

  1. IOS开发之多线程 -- GCD的方方面面

    前言:这篇GCD的博文是本人阅读了很多海内外大神的关于GCD的文章,以及结合之前自己对GCD的粗浅的认识,然后取其精华,去其槽粕,综合起来的笔记,而且是尽可能的以通熟易懂的并且是正确的理论论述方式呈现 ...

  2. iOS开发-多线程编程技术(Thread、Cocoa operations、GCD)

    简介 在软件开发中,多线程编程技术被广泛应用,相信多线程任务对我们来说已经不再陌生了.有了多线程技术,我们可以同做多个事情,而不是一个一个任务地进行.比如:前端和后台作交互.大任务(需要耗费一定的时间 ...

  3. iOS开发之多线程(NSThread、NSOperation、GCD)

    整理一些多线程相关的知识. 并行 & 并发 1.并行:并行是相对于多核而言的,几个任务同时执行.2.并发:并发是相对于单核而言的,几个任务之间快速切换运行,看起来像是"同时" ...

  4. iOS开发之多线程技术

    本篇争取一篇讲清讲透,依然将通过四大方面清晰的对iOS开发中多线程的用法进行详尽的讲解: 一.什么是多线程 1)多线程执行原理 2)线程与进程 3)多线程的优缺点 二.我们为什么要用多线程编程技术 三 ...

  5. iOS开发-多线程开发之线程安全篇

    前言:一块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源,比如多个线程访问同一个对象.同一个变量.同一个文件和同一个方法等.因此当多个线程访问同一块资源时,很容易会发生数据错误及数据不安 ...

  6. iOS开发之多线程技术(NSThread、OperationQueue、GCD)

    在前面的博客中如果用到了异步请求的话,也是用到的第三方的东西,没有正儿八经的用过iOS中多线程的东西.其实多线程的东西还是蛮重要的,如果对于之前学过操作系统的小伙伴来说,理解多线程的东西还是比较容易的 ...

  7. iOS开发之多线程技术——GCD篇

    本篇将从四个方面对iOS开发中GCD的使用进行详尽的讲解: 一.什么是GCD 二.我们为什么要用GCD技术 三.在实际开发中如何使用GCD更好的实现我们的需求 一.Synchronous & ...

  8. iOS开发之多线程技术—GCD篇

    本篇将从四个方面对iOS开发中GCD的使用进行详尽的讲解: 一.什么是GCD 二.我们为什么要用GCD技术 三.在实际开发中如何使用GCD更好的实现我们的需求 一.Synchronous & ...

  9. iOS开发之多线程技术——NSOperation篇

    本篇将从四个方面对iOS开发中使用到的NSOperation技术进行讲解: 一.什么是NSOperation 二.我们为什么使用NSOperation 三.在实际开发中如何使用NSOperation ...

随机推荐

  1. try {}里有一个return语句 finally执行顺序

    先看例子 package example; class Demo{ public static void main(String args[]) { int x=1; System.out.print ...

  2. Zabbix监控告警

    一 钉钉告警 1.1.1 添加钉钉机器人 发起群聊 创建完群聊选择,机器人管理 选择你要绑定的群聊 复制下面地址留用 1.1.2 编写钉钉告警脚本 安装requests库,HTTP客户端, # yum ...

  3. [Javascript] Different ways to create an new array/object based on existing array/object

    Array: 1. slice() const newAry = ary.slice() 2. concat const newAry = [].concat(ary) 3. spread oprea ...

  4. Android DiskLruCache全然解析,硬盘缓存的最佳方案

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/28863651 概述 记得在非常早之前.我有写过一篇文章Android高效载入大图. ...

  5. How to remove a Data Guard Configuration from Primary Database (文档 ID 733794.1)

    APPLIES TO: Oracle Database - Enterprise Edition - Version 10.1.0.2 to 11.2.0.3 [Release 10.1 to 11. ...

  6. 【Codeforces Round #446 (Div. 2) A】Greed

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 贪心选容量大的瓶子就好 [代码] #include <bits/stdc++.h> #define int long l ...

  7. 【Codeforces Round #429 (Div. 1) B】Leha and another game about graph

    [链接]点击打开链接 [题意] 给出一个连通图,并给每个点赋一个d值0或1或-1,要求选出一个边的集合,使得所有的点i要么d[i] == -1,要么  dgree[i] % 2 == d[i],dgr ...

  8. centos7 分区满了,分析哪个目录或文件占用空间-小叶-51CTO博客

    原文:centos7 分区满了,分析哪个目录或文件占用空间-小叶-51CTO博客 du -sh 例如: [root@zabbix ~]# du -sh /var/* 0 /var/adm 132M / ...

  9. 【Codeforces Round #434 (Div. 2) B】Which floor?

    [链接]h在这里写链接 [题意] 在这里写题意 [题解] 枚举每层有多少个公寓就好. 要注意,每次都要从1到100判断,一下那个公寓该不该出现在那一层. 多个答案,如果答案是一样的.也算是唯一的.  ...

  10. Java 泛型-泛型类、泛型方法、泛型接口、通配符、上下限

    泛型: 一种程序设计语言的新特性,于Java而言,在JDK 1.5开始引入.泛型就是在设计程序的时候定义一些可变部分,在具体使用的时候再给可变部分指定具体的类型.使用泛型比使用Object变量再进行强 ...