多线程

  • Post author:
  • Post category:其他


一.进程的五态模型

二.线程是进程的基本执行单元,进程的所有任务都在线程中执行,每个进程都会至少有一个线程,称为主线程(UI线程)

三.为什么要用多线程

耗时操作比如网络请求,图片加载,文件处理,数据存储,任务执行,导致UI卡顿,体验不好

四.任务的执行方式

串行:多个任务按顺序执行,耗时为多个任务时间之和

并行:多个任务同时并发执行,耗时为最大任务耗时

五. 多线程的实现原理

对于单核操作系统,宏观上是并行,微观上是串行,操作系统会以操作片轮转调度的方式,来分配时间段,每个时间只允许一个线程执行

对于多核操作系统,是正真的并行

六.多线程的优缺点

优点:简化了编程模型

更加轻量级

提高了执行效率

提高资源利用率

缺点

多线程要解决的最大的问题就是资源共享和线程读写问题

增加程序设计复杂性

占用内存空间

增大CPU开销

七. 多线程的实现技术方案

pThread   基于C++语言,移植性好,用的少

NSThread  苹果封装后的,面向对象的

GCD  为多核提供的,用的Block封装了c,不需要关注生命周期

NSOperation 对gcd的封装


****************************


pThread


**********************************


#import


<pthread.h>


– (


IBAction


)pThread:(


UIButton


*)sender {




NSLog


(


@”


我在主线程中执行





);




//


创建线程




pthread_t


pthread;




pthread_create


(&pthread,


NULL


,


run


,


NULL


);

}


void


*run(


void


* data){




NSLog


(


@”


我在子线程中执行





);




for


(


int


i =


1


; i<


10


; i++) {




NSLog


(


@”%d”


,i);




sleep


(


1


);

}




return


NULL


;

}


****************************

NSThread

**********************************

#pragmamark – NSThread


– (


IBAction


)NSThread:(


id


)sender {




NSLog


(


@”


我在主线程中执行


–NSThread”


);




//1.


通过


alloc init


创建线程并执行




NSThread


* thread1 = [[


NSThread


alloc


]


initWithTarget


:


self


selector


:


@selector


(runThread1)


object


:


nil


];


[thread1


setName


:


@”NSThreadName1″


];


//


设置线程名


[thread1


setThreadPriority


:


0.2


];


//


设置线程执行前的延时时间


[thread1


start


];




NSLog


(


@”%@”


,[thread1


name


]);




NSThread


* thread2 = [[


NSThread


alloc


]


initWithTarget


:


self


selector


:


@selector


(runThread1)


object


:


nil


];


[thread2


setName


:


@”NSThreadName2″


];


[thread2


start


];




NSLog


(


@”%@”


,[thread2


name


]);




//2.


通过


detachNewThreadSelector


方式创建并执行线程

//   [NSThread detachNewThreadSelector:@selector(runThread1) toTarget:selfwithObject:nil];




//3.


通过


performSelectorInBackground


方式创建并执行线程

//   [self performSelectorInBackground:@selector(runThread1) withObject:nil];

}


-(


void


)runThread1{




NSLog


(


@”


我在子线程中执行


–NSThread”


);




for


(


int


i =


1


; i<=


10


; i++) {




NSLog


(


@”%d”


,i);




sleep


(


1


);




if


(i ==


10


) {


[


self


performSelectorOnMainThread


:


@selector


(runMainThread)


withObject


:


nil


waitUntilDone


:


YES


];

}

}

}


-(


void


)runMainThread{




NSLog


(


@”


回到主线程执行!!!





);

}


****************************

GCD

**********************************

#pragma mark — 1 基本gcd


-(


IBAction


)gcd_1{




LOG




dispatch_async


(


dispatch_get_global_queue


(


DISPATCH_QUEUE_PRIORITY_DEFAULT


,


0


), ^(


void


){




//


开辟子线程执行耗时任务




NSLog


(


@”GCD


子线程





);




LOG


[


NSThread


sleepForTimeInterval


:


2


];




dispatch_async


(


dispatch_get_main_queue


(),^(


void


){




//


返回主线程




NSLog


(


@”


回到主线程执行!!!





);




LOG

});

});

}

#pragma mark — 2 在定义优先级的情况下,会按照优先级去执行;在不定义优先级的情况下,默认多个gcd是全局并发执行


-(


IBAction


)gcd_2{




LOG




//DISPATCH_QUEUE_PRIORITY_HIGH


优先级




dispatch_async


(


dispatch_get_global_queue


(


DISPATCH_QUEUE_PRIORITY_LOW


,


0


), ^{




NSLog


(


@”task 1″


);


LOG

});




dispatch_async


(


dispatch_get_global_queue


(


DISPATCH_QUEUE_PRIORITY_HIGH


,


0


), ^{




NSLog


(


@”task 2″


);


LOG

});




dispatch_async


(


dispatch_get_global_queue


(


DISPATCH_QUEUE_PRIORITY_DEFAULT


,


0


), ^{




NSLog


(


@”task 3″


);


LOG

});

}

#pragma mark — 3 自定义队列,只开辟了一条线程,会按照顺序执行,可以通过修改参数定义是并行还是串行


-(


IBAction


)gcd_3{




//dispatch_queue_create(“com.test.gcd.queue”,NULL);//


参数为


NULL


说明是串行队列




//dispatch_queue_create(“com.test.gcd.queue”,DISPATCH_QUEUE_CONCURRENT);//


参数为


DISPATCH_QUEUE_CONCURRENT


说明是并行队列




dispatch_queue_t


queue=


dispatch_queue_create


(


“com.test.gcd.queue”


,


NULL


);




dispatch_async


(queue,^{




NSLog


(


@”


自定义子线程


1″


);




LOG


[


NSThread


sleepForTimeInterval


:


2


];




NSLog


(


@”


结束自定义子线程


1″


);

});




dispatch_async


(queue,^{




NSLog


(


@”


自定义子线程


2″


);




LOG


[


NSThread


sleepForTimeInterval


:


2


];




NSLog


(


@”


结束自定义子线程


3″


);

});




dispatch_async


(queue,^{




NSLog


(


@”


自定义子线程


3″


);




LOG


[


NSThread


sleepForTimeInterval


:


2


];




NSLog


(


@”


结束自定义子线程


3″


);

});

}

#pragma mark — 4 多个线程结束后的统一回调处理 – group


-(


IBAction


)gcd_4{




dispatch_queue_t


queue =


dispatch_queue_create


(


“com.test.gcd.queue”


,


DISPATCH_QUEUE_CONCURRENT


);




dispatch_group_t


group =


dispatch_group_create


();




dispatch_group_async


(group, queue, ^{




NSLog


(


@”start tast 1″


);


LOG


[


NSThread


sleepForTimeInterval


:


2


];




NSLog


(


@”end tast 1″


);

});




dispatch_group_async


(group, queue, ^{




NSLog


(


@”start tast 2″


);


LOG


[


NSThread


sleepForTimeInterval


:


2


];




NSLog


(


@”end tast 2″


);

});




dispatch_group_async


(group, queue, ^{




NSLog


(


@”start tast 3″


);


LOG


[


NSThread


sleepForTimeInterval


:


2


];




NSLog


(


@”end tast 3″


);

});




dispatch_group_notify


(group, queue, ^{




NSLog


(


@”all task over”


);


LOG




dispatch_sync


(


dispatch_get_main_queue


(),^(


void


){




NSLog


(


@”


回到主线程刷新


UI”


);


LOG

});

});

}


****************************

GCD应用

**********************************

#pragma mark – 单例 – 通过dispatch_once方法,只执行一次


– (


IBAction


)single:(


id


)sender {


[


TestSingle


instance


];

}

#pragma mark – 延迟执行


– (


IBAction


)delayRun:(


id


)sender {




NSLog


(


@”——begin—–”


);




dispatch_after


(


dispatch_time


(


DISPATCH_TIME_NOW


, (


int64_t


)(


2


*


NSEC_PER_SEC


)),


dispatch_get_main_queue


(), ^{




NSLog


(


@”—–


延迟执行


—–”


);

});

}


****************************

NSOperation

**********************************

//NSOperation 对gcd的封装

//1 有两种使用方式

//    (1)NSInvocationOperation和NSBlockOperation

//    (2)自定义类继承NSOperation

//2 相关概念

//(1).NSOperationQueue 队列,线程池

//a.addOperation

//b.setMaxConcurrentOperationCount

//(2).状态

//ready, cancelled , executing ,finished , asynchronous

//(3).依赖 addDependency

#pragmamark – NSInvocationOperation


-(


IBAction


)NSOperation_1:(


id


)sender{




LOG




//1NSInvocationOperation


是非并发的,也就是说同步执行的,会阻塞当前的线程




NSInvocationOperation


* invocationOperation = [[


NSInvocationOperation


alloc


]


initWithTarget


:


self


selector


:


@selector


(invocationOperation)


object


:


nil


];


[invocationOperation


start


];




NSLog


(


@”end”


);

}


-(


void


)invocationOperation{




LOG




for


(


int


i =


0


; i<


3


; i++) {




NSLog


(


@”invocationOperation %d”


,i);


[


NSThread


sleepForTimeInterval


:


1


];

}

}

#pragmamark – NSBlockOperation


-(


IBAction


)NSOperation_2:(


id


)sender{




LOG




//2NSBlockOperation


同步执行




NSBlockOperation


* blockOpertion = [


NSBlockOperation


blockOperationWithBlock


:^{




LOG




for


(


int


i =


0


; i<


3


; i++) {




NSLog


(


@”invocationOperation %d”


,i);


[


NSThread


sleepForTimeInterval


:


1


];

}

}];


[blockOpertion


start


];

}

#pragma mark – 异步方式实现


-(


IBAction


)NSOperation_3:(


id


)sender{




LOG




//


以上两种都是同步的,真正使用中异步用的多,使用


NSOperation





NSOperationQueue


结合的方式实现异步




NSBlockOperation


* blockOpertion = [


NSBlockOperation


blockOperationWithBlock


:^{




LOG




for


(


int


i =


0


; i<


3


; i++) {




NSLog


(


@”invocationOperation %d”


,i);


[


NSThread


sleepForTimeInterval


:


1


];

}

}];




if


(!


self


.


operationQueue


) {




self


.


operationQueue


= [[


NSOperationQueue


alloc


]


init


];

}


[


self


.


operationQueue


addOperation


:blockOpertion];




NSLog


(


@”end”


);

}

#pragma mark – 自定义NSOperation


– (


IBAction


)customOperation:(


id


)sender {




if


(!


self


.


operationQueue


) {




self


.


operationQueue


= [[


NSOperationQueue


alloc


]


init


];

}




//


设置并发最大线程数,同一时刻允许执行几条线程


[


self


.


operationQueue


setMaxConcurrentOperationCount


:


4


];




CustomOperation


* customOpar1 = [[


CustomOperation


alloc


]


initWithOperationName


:


@”customOpar1″


];


[


self


.


operationQueue


addOperation


:customOpar1];




CustomOperation


* customOpar2 = [[


CustomOperation


alloc


]


initWithOperationName


:


@”customOpar2″


];


[


self


.


operationQueue


addOperation


:customOpar2];




CustomOperation


* customOpar3 = [[


CustomOperation


alloc


]


initWithOperationName


:


@”customOpar3″


];


[


self


.


operationQueue


addOperation


:customOpar3];




CustomOperation


* customOpar4 = [[


CustomOperation


alloc


]


initWithOperationName


:


@”customOpar4″


];


[


self


.


operationQueue


addOperation


:customOpar4];




//


依赖




//


前者依赖于后者


不能造成循环依赖,结果是一个个执行,


2314


一次执行


[customOpar4


addDependency


:customOpar1];


[customOpar1


addDependency


:customOpar3];


[customOpar3


addDependency


:customOpar2];




NSLog


(


@”end”


);

//    运行结果:

//   end

//   customOpar1 , 0

//   customOpar1 , 1

//    customOpar1 , 2   说明:异步执行

//    运行结果:

//   end

//   customOpar3 , 0

//   customOpar4 , 0

//   customOpar2 , 0

//   customOpar1 , 0

//   customOpar3 , 1

//   customOpar4 , 1

//   customOpar1 , 1

//   customOpar2 , 1

//   customOpar4 , 2

//   customOpar1 , 2

//   customOpar2 , 2

//    customOpar3 , 2   说明:并发执行

}


********************


多线程资源争夺问题解决





加锁


****************************


#import


<Foundation/Foundation.h>


@interface


TicketManager :


NSObject


-(


void


)startToSale;

@end


#import


“TicketManager.h”


#define Total


50


@interface


TicketManager


()


@property


int


tickets;


//


剩余票数


@property


int


saleCount;


//


卖出票数


@property


(


strong


,


nonatomic


)


NSThread


* threadBJ;


@property


(


strong


,


nonatomic


)


NSThread


* threadSH;


@property


(


strong


,


nonatomic


)


NSThread


* threadXA;


@property


(


strong


,


nonatomic


)


NSCondition


* ticketCondition;


//


第二种加锁方式

@end


@implementation


TicketManager


-(


instancetype


)init{




if


(


self


= [


super


init


]) {




self


.


tickets


=


Total


;




self


.


ticketCondition


= [[


NSCondition


alloc


]


init


];


//


初始化锁




self


.


threadBJ


= [[


NSThread


alloc


]


initWithTarget


:


self


selector


:


@selector


(sale)


object


:


nil


];


[


self


.


threadBJ


setName


:


@”BJ_thread”


];




self


.


threadSH


= [[


NSThread


alloc


]


initWithTarget


:


self


selector


:


@selector


(sale)


object


:


nil


];


[


self


.


threadSH


setName


:


@”SH_thread”


];




self


.


threadXA


= [[


NSThread


alloc


]


initWithTarget


:


self


selector


:


@selector


(sale)


object


:


nil


];


[


self


.


threadXA


setName


:


@”XA_thread”


];

}




return


self


;

}


-(


void


)sale{




while


(


true


) {




//


第一种加锁方式




// @synchronized(self) {






//


第二种加锁方式


[


self


.


ticketCondition


lock


];




//self.tickets > 0


说明还有票可以卖




if


(


self


.


tickets


>


0


) {


[


NSThread


sleepForTimeInterval


:


0.2


];




self


.


tickets


–;




self


.


saleCount


=


Total





self


.


tickets


;




NSLog


(


@”


当前线程


:%@ ,


剩余票数


:%d ,


售出票数


:%d”


,[


NSThread


currentThread


].


name


,


self


.


tickets


,


self


.


saleCount


);

}




//


第二种加锁方式


[


self


.


ticketCondition


unlock


];

}


//    }

}


-(


void


)startToSale{


[


self


.


threadBJ


start


];


[


self


.


threadSH


start


];


[


self


.


threadXA


start


];

}

@end

调用:


-(


IBAction


)buyTicket:(


id


)sender{




//


多线程要解决资源共享问题,加锁




TicketManager


* manager = [[


TicketManager


alloc


]


init


];


[manager


startToSale


];

}



版权声明:本文为mnbvcxz111123原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。