码迷,mamicode.com
首页 > 移动开发 > 详细

iOS中关于多线程的实现方案的介绍(一)

时间:2015-11-07 17:32:06      阅读:219      评论:0      收藏:0      [点我收藏+]

标签:

什么是进程

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

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

什么是线程

>  1个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程)

>  线程是进程的基本执行单元,一个进程(程序)的所有任务都在线程中执行

什么是多线程

>  1个进程中可以开启多条线程,每条线程可以并发(同时)执行不同的任务

>  进程 à 车间,线程 à 车间工人

>  多线程技术可以提高程序的执行效率

多线程的原理啊

>  同一时间,CPU只能处理1条线程,只有1条线程在工作(执行)

>  多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)

>  如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象

多线程优缺点

优点:

>  能适当提高程序的执行效率

>  能适当提高资源利用率(CPU、内存利用率)

缺点:

>  开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能

>  线程越多,CPU在调度线程上的开销就越大

>  程序设计更加复杂:比如线程之间的通信、多线程的数据共享

关于主线程(iOS)

什么是主线程

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

主线程的作用

>     显示\刷新UI界面

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

主线程的使用注意

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

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

 

iOS开发中,用于多线程开发技术,主要由以下几种

技术方案

简介

语言

生命周期

使用频率

Pthread

ü   一套通用的多线程API

ü   适用于Unix\linux\window等系统

ü   可跨平台,可移植

ü   适用难度大

C

程序员管理

几乎不用

NSThread

ü   使用更加面向对象

ü   简单易用,可直接操作线程对象

OC

程序员管理

偶尔使用

GCD

ü   用于替代NSThread等线程技术

ü   充分利用设备的多核

C

自动管理

经常适用

NSOperation

ü   基于GCD(底层是GCD)

ü   比GCD多一些更简单使用的功能

ü   适用更加面向对象

OC

自动管理

经常适用

关于pthread

由于pthread几乎不用,所我将用几个简单的案例说明,直接上代码

 1 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
 2     
 3     [self began];
 4 }
 5 
 6 
 7 
 8 // iOS开发,一般C语言的框架.h文件没有注释
 9 // http://baike.baidu.com
10 
11 // 使用pthread创建线程
12 - (void)began
13 {
14     // 声明一个线程变量
15     pthread_t threadId;
16     
17     //传给在线程中运行的函数的参数
18     id str = @"hello";
19     
20     
21     pthread_create(&threadId, NULL, run, (__bridge void *)(str));
22 }
23 // 线程中运行的耗时函数
24 void *run(void *param)
25 {
26     NSString *str = (__bridge NSString *)(param);//接收穿件来的函数
27     
28     // 耗时操作放在这里执行
29     for (int i = 0; i < 20000; i++) {
30         NSLog(@"%@----%@", [NSThread currentThread], str);
31     }
32     //[NSThread currentThread]:打印当前线程
33     
34     return NULL;
35 }

四个参数的解释

      1. 要开的线程的变量

     2. 线程的属性

     3. 要在这个子线程执行的函数(任务)

     4. 这个函数(任务)需要传递的参数

 

关于NSThread

我也讲通过代码来介绍NSThread

首先是创建NSThread的三种方式

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

    [self began1];
    
}

//创建线程方法1
- (void)begin1
{
    //实例化一个线程对象,这个方法有利于线程属性的应用
    NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"hellow"];

    //此方法需要手动发个线程开始工作,启动线程,在新开的线程中执行run方法
    [thread start];
}

//创建线程方法2
- (void)begin2
{
    [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"函数参数"];
}

//创建线程方法3
- (void)begin3
{
    [self performSelectorInBackground:@selector(run:) withObject:@"函数参数"];
}

// 耗时操作,子线程中进行的函数
- (void)run:(NSString *)str
{
    for (int i = 0; i < 10; i++) {
        NSLog(@"%@--%d", [NSThread currentThread], i);
    }
}

NSThread的属性

- (void)test4
{
    NSThread *threadA = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"hello"];
    //线程名字,在[NSTread currentThread]的打印中可以看到
    threadA.name = @"thraed A";
    
    // 线程优先级
    // 是一个浮点数,0.0~1.0。 默认值 0.5
    // 开发的时候,一般不去修改优先级的值。
    // 优先级,必须调用很多次的时候,才能体现出来。
    threadA.threadPriority = 0.1;
    
    // 开始工作
    [threadA start];
    
    
    NSThread *threadB = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"hello"];
    
    threadB.name = @"thraed B";
    
    // 线程优先级
    // 是一个浮点数,0.0~1.0。 默认值 0.5
    threadB.threadPriority = 1.0;
    
    // 开始工作
    [threadB start];
}

控制线程状态

  1.启动线程

  -(void)start;

  2.阻塞线程

  +(void)sleepUntilDate:(NSDate *)date;

  +(void)sleepForTimeInterval:(NSTimeInterval)ti;

  3.强制停止线程

  +(void)exit;

  注意:程序一旦进入停止(死亡)状态,就不能再启动任务.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self began];
}


- (void)began
{
    // 1. 新建一个线程
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
    
    // 2. 放到可调度线程池,等待被调度。 这时候是就绪状态
    [thread start];
}

- (void)run
{
    //进来就阻塞(休息)几秒
    [NSThread sleepForTimeInterval:5.0];
    //指定休息到什么时候
    [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]];
    
    //休息玩进入耗时操作
    for (int i = 0; i < 20; i++) {
        //也可再满足某一条件后进入休息
        if (i == 10) {
            [NSThread sleepForTimeInterval:2.0];
        }
        //也可让他在某一条件下终止线程的执行
        if (i == 15) {
            [NSThread exit];
        }
        NSLog(@"%@---%d",[NSThread currentThread], i);
    }
    NSLog(@"线程结束");

}

多线程的安全隐患

  1.一块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源

  2.当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题

可通过互斥锁来解决安全隐患问题

  互斥锁的使用格式

    @synchronized(锁对象,一般为self){//需要锁住的代码块}

    注意:锁定一份代码只能用一把锁,用多把锁是无效的

互斥锁的有缺点

    优点:能有效防止因多线程抢夺资源造成的数据安全问题

    缺点:需要消耗大量的CPU资源

但是苹果公司不推荐使用互斥锁,因为性能太差了.
所以,苹果公司默认将所有程序的更新UI都在主线程进行,也就不会出现多个线程改变一个资源
而在主线程更新UI的好处有"
  1.只在主线程更新UI,就不会出现多个线程同时改变一个UI控件
  2.主线程的优先级最高,也就意味着UI的更新优先级高,会让用户感觉很流畅,提升客户体验;\.
 
 
关于原子atomic和非原子nonatomic属性
  atomic:原子属性,为setter方法加锁(默认就是atomic),线程安全的,需要消耗大量的资源
  nonatomic:非原子属性,不会为setter方法加锁,非线程安全,适合内存小的移动设备,iOS开发中基本用该属性.

iOS中关于多线程的实现方案的介绍(一)

标签:

原文地址:http://www.cnblogs.com/yyns/p/4945628.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!