您的位置:首页 > 移动开发 > IOS开发

ios的多线程

2016-01-13 23:14 295 查看
多线程第一天
多线程的作用:耗时操作不卡主屏幕
//任务执行的两种方式: 同步/异步
1->同步有顺序.异步没有先后顺序
异步执行 无法控制速度.和进程
多线程就是研究异步执行的
开线程:performSelectoerInBackGround

进程/线程
进程的作用:维持程序的存在
进程:在系统中正在运行的一个应用程序
每个进程之间是独立的.每个进程有一个独立的保护的内存空间

线程:
一个进程至少要有一个线程
线程是进程的基本执行单元.一个进程的所有任务都在线程中执行

多线程:一个进程可以开启多个线程 ,多个可以”同时”执行不同的任务

多线程可以解决程序阻塞的问题
多程序可以解决程序的执行效率的问题

多线程的执行原理
“多线程的同时执行”,是cpu快速的在多个线程之间的切换
cpu在多个线程之间做切换操作

多线程的优缺点
优点:能适当的提高程序的执行效率
        能适当的提高资源的利用率(cpu 内存)
        线程上的任务执行完成后 线程会自动销毁
缺点:
1⃣️开启线程需要占用一定的内存空间(开辟512kb)
2⃣️如过开启大量的线程  会真用大量的内存空间  减低程序的性能
3⃣️线程越多.cpu在调用线程上的开销就越大  1->cup开销2->内存 3->时间

线程保存在栈   区  (Stack space)
Creation time  90毫秒
4⃣️程序设计更加复杂, 比如多线程的数据共享.线程间的通信(聊天)

主线程
一个程序运行后,默认会开启一个线程,成为主线程或者”ui线程”
程序一启动主线程 操作都是ui操作
主线程一般用来刷仙UI界面 处理是事件
不要将耗时操作放到主线程 

实现异步执行:开线程 

iOS中多线程的指数方案
1⃣️ POSIX可移植的线程的操作系统接口(Protable Operating System InterFace )
pthread :多线程的API 跨平台/可移植
2⃣️NSthread :面向对象 
3⃣️GCD 替代NSthread 充分利用设备的多核
语言C
4⃣️NSOperation:基于GCD

pthread:
1.导入头文件
2phtread_creat(___) 里面都是传地址
参数一 :子线程的编号/代号/ID/传入地址
参数二:子线程的属性.此处不知设置线程属性 传入NULL 空指针 nil是空对象
参数三:指定子线程执行的函数,
void *       (*)                  (void *)
 返回值            函数名                  函数的参数

c语言的三大要数:返回值,函数名.函数的参数
void* :标识可以纸箱任何地址的指针,类似于oc中的id(万能指针可以指向任何对象的地址)
函数的地址: 就是函数名

prthread_t 数据类型  ID

返回值是int  如果成功 创建子程序成功返回0;如果失败返回非零—>成功的原因只有一个
/**

 *  pthrad演练,创建子线程

 */

- (void)pthreadDemo

{

   
NSLog(@"pthreadDemo %@",[NSThread

currentThread]);

   

   
/*

    
参数1 :

子线程的编号/代号/ID.传入地址

    
参数2 :

子线程的属性.此处不设置线程属性.传入

NULL.空指针.nil是空对象

    
参数3 :

指定子线程执行的函数

     void *     (*)     (void *)

    
返回值   

函数名   

函数的参数

     void * :
表示可以指向任何地址的指针.类似于OC中的id(万能指针,可以指向任何对象的地址)

    
函数的地址
:
就是函数名.

    
参数4 :

传入指定子线程执行的函数参数中的数据

    

    
返回值
: int,如果创建子线程成功,返回0;如果失败返回非零.因为成功的结果只有一个,失败的原因有很多.

    

     <NSThread: 0x7fcd1b507490>{number = 1, name = main}

     number
等于1的时候,是主线程

    

     <NSThread: 0x7fcd1ca041b0>{number = 2, name = (null)}

     number
不等于1的时候,是子线程

    
提示
:
不要纠结number到底等于几,因为是CPU分配的,只是线程创建的编号的累加

    

     */

   

   
//
参数1

   
pthread_t
ID;

   
int
result =
pthread_create(&ID,

NULL,

demo,

NULL);

   
if
(result ==
0) {

       
NSLog(@"成功");

    }
else
{

       
NSLog(@"失败");

    }

}

//

指定子线程执行的函数
void

*demo(void

*param)

{

   
NSLog(@"demo %@",[NSThread

currentThread]);

   
return
NULL;
}

__bridge桥接
在MRC环境下.谁申请,谁释放
在Arc环境下,编译器在编根据译的时候,会根据代码的结构,在合适的位置添加release,retain,sutolerease语句
在ARC环境下,编译器 不会管理C语言申请的内存空间
桥接目的:告诉编译器,什么都不做
在mrc环境下需要使用桥接么?不需要,因为该环境下,内存是手动管理的

NStread创建线程的三种方式
- (void)touchesBegan:(NSSet<UITouch

*> *)touches withEvent:(UIEvent

*)event

{

    [self

threadDmoe3];

}

//

隐式创建

- (void)threadDmoe3

{

   
// @interface NSObject (NSThreadPerformAdditions)

   
//
方便凡是继承自NSObject的对象,都可以很方便的调用线程相关的方法

    [self

performSelectorInBackground:@selector(demo:)

withObject:@"perform"];

}

//

类方法

- (void)threadDmoe2

{

   
// detach :
分离

   
//
无法拿到线程对象,无法手动开启子线程

   
//
自动启动子线程

    [NSThread

detachNewThreadSelector:@selector(demo:)

toTarget:self

withObject:@"detach"];

}

//

对象方法

- (void)threadDmoe1

{

   
// Target :
哪个对象

   
// selector :
哪个对象的哪个方法

   
//
执行哪个对象的哪个方法

   

   
//
创建线程对象

   
NSThread
*thread = [[NSThread

alloc]

initWithTarget:self

selector:@selector(demo:)

object:@"alloc"];

   
//
启动子线程

    [thread
start];

}

- (void)demo:(id)param

{

   
NSLog(@"%@ %@",param,[NSThread

currentThread]);
}
 

线程的状态 线程的生命周期
1⃣️ alloc init :内存中出现一个线程对象 :状态 :新建
2⃣️ start方法  出现一个可调度的线程池 线程对象进入线程的可调度线程池
nsthread 只能做到这一步,后面的调用由cpu负责调用  也就是只能到达新建状态

一下是CUP操作的
3⃣️ Runable 就绪状态
 cou调度当前线程 运行状态 .当CPU调用其他线程,则又进入就绪状态,
4⃣️ 如果调用了sleep方法/等待同步锁  该线程会从可调度线程池中移除,但没有销毁,进入内存中,进入阻塞状态;
�️ sleep到时,得到同步锁 该线程回到可调度线程池, 结束阻塞状态进入就绪状态,
6⃣️结束完毕,销毁,正常死亡
7⃣️非正常死亡

线程的状态

06线程的属性 
线程的执行是由CPU决定的,我们控制不了
name:标识线程 追踪线程  追踪bug

threadPriority 优先级 范围是0.0-1.0 默认是0.5
不能决定线程之间的先后顺序,只是线程�更多的机会呗CPu执行
开发建议,千万不要设置threadPriority

打印内存大小   子线程的内存空间的大小  单位kb
NSLog(@”%tu”,[NSthread currentThread].stackSize);  
主线程和子线程都是512kb

07多线程操作共享资源的问题(缺点)
共享资源:一个对象 一个变量  一个文件
共享资源:全局的对象,文件,可以被其他对象访问的资源

当多个线程错做同一块资源时  很容易引发数据错乱和数据安全
数据错乱理论依据:多个线程之间的切换
@synchronized(self)
互斥锁,同步锁  利用了线程的同步技术
互斥锁和同步锁的特点 : 能够保证被锁定的代码同一时间只能由一个线程访问或者访问,间接的实现了一个单线程.
锁定的范围是共享的资源读写部分,而且锁定的范围必须小
self :锁对象之一 ,任何继承自noObject的对象都是锁对象,内部都有一把锁,默认是开启的
锁对象必须是全局的对象,不能是局部对象.
局部的锁对象 每次线程执行都是一个新的对象 锁不住属性.self是最方便获取的全局锁对象

8原子属性 线程”安全的"
nonatomic
atomic 原子属性.默认的
 保证同一时间只有一个线程能够写入,但是同一时间多个线程都可以取值
单写多读. 单个线程写入.多核线程可以读取; 所以不是绝对的安全
atomic 本身就有一把锁(自旋锁)写在set方法里面 我们看不到 自旋锁看不到.

nonatomic和atomic对比
atomic 线程安全 需要消耗大量的资源
nonatomic  非线程的.适合内存次小的移动设置

ios开发建议:声明为nonatomic 

模拟原子属性 重写set,get方法,我们重写setget方法,没有_属性,所以要用合成指令@synthesize obj=_obj;
互斥锁:如果发现其他线程正在执行锁定代码,线程会进入休眠(就绪状态) 等其他线程时间到开锁后,线程会被唤醒(执行)
自旋锁:如果发现其他线程正在锁定代码.线程会以死循环的方式一直等待

线程安全:
多个线程同时操作共享资源是不安全的,多个线程同时操作一个全局变量
线程安全:在多个线程进行读写操作时,仍然能够保证数据的正确

主线程(UI线程):
几乎所有UIKI类库的类都是线程不安全的,所以更新UI的操作都在主线程 主线程唯一,没有多线程,防止同时操作.为了不出错,所以控件要求都在主线程上面执行
 所有包含NSMUtable的类都是线程不安全的
为什么UIKIT不加锁,,保证流畅

查看4,40需求分析
一旦重写loadView  控制器就不会从SB中加载当self.view==nil的时候就会调用loadView
线程间的通信 当一个线程中的数据传递到其他线程,

当创建对象 不希望立即销毁, 用strong 直接引用计数加1,不让他销毁;
控件strong和weak的 strong只会出现重复强引用,不影响
用weak只是保存,
strong强引用 引用计数加1;
拖控件连线的时候为什么用weak:  拖到sb的时候subViews已经对控件有一个强引用

自动释放池

 消息循环  类似于一个死循环.消息是一个动作,捕捉消息的死循环 
作用:1保证程序不退出
        2.捕捉交互,传递响应 检测事件的

 内存泄露 该释放的没有释放
内存溢出 内存满了
野指针 :不该释放的释放了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  多线程基础