君实在学明白。首先来一个web.xml文件。与男友恋爱里受情敌挑战及男友的匪关心。

致力来肯定起坐,今天自己思与公聊聊线程的因由即是——当然是对准一个共产党人的思想觉悟,为庶人透析生命,讲解你正蒙圈的知识点,或者想排除脑袋才意识这么简单的技能方案。

许多总人口法线程,迷迷糊糊;很多人数问线程,有所期待;也来很多人写线程,分享认知给正全力的小青年,呦,呦,呦呦。但是,你真了解线程么?你真的会用几近线程么?你实在学明白,问明了,写清楚了么?不管您知道不晓,反正我不亮,但是,没随,你看了,你虽知了。


1.创造一个动态的web工程

仍记得有高中的下午,拿在某篇连载在朗诵,遗憾之究竟让自己记住了作者姚非拉。

前言

  • 提到线程,那就是不得不提CPU,现代底CPU有一个坏关键之性状,就是时空片,每一个博CPU的职责只能运行一个时刻片规定之辰。
  • 实则线程对操作系统来说即使是相同段落代码和运行时数。操作系统会为每个线程保存有关的多少,当属接来自CPU的时间片中断事件不时,就见面按照一定规则从这些线程中甄选一个,恢复它的周转时数,这样CPU就可继续执行这个线程了。
  • 啊即是实际就单核CUP而言,并从未法落实真正含义及的产出执行,只是CPU快速地于差不多修线程之间调度,CPU调度线程的工夫足够快,就招了差不多线程并发执行的假象。并且就单核CPU而言多线程可以化解线程阻塞的问题,但是那本人运行效率并从未加强,多CPU的相互运算才真的化解了运转效率问题。
  • 系统面临正运作的各级一个应用程序都是一个进程,每个过程系统都见面分配给她独立的内存运行。也就是说,在iOS系统中备受,每一个用都是一个过程。
  • 一个进程的保有任务还以线程中展开,因此每个过程至少要出一个线程,也就算是主线程。那多线程其实就是一个历程被多条线程,让有任务并发执行。
  • 基本上线程在定意义上实现了经过内之资源共享,以及效率的升级换代。同时,在一定水平上相对独立,它是程序执行流的卓绝小单元,是经过被的一个实体,是执行顺序太核心的单元,有友好栈和寄存器。
  • 面这些公是勿是都知晓,但是自己偏偏要说,哦呵呵。既然我们聊线程,那咱们不怕优先从线程开刀。

2.导入springMvc所要之jar包(这里可以错过网上搜,资源来众多)

故事中的老小问老公“你说咱们最终见面结束婚么?”男人说“不知情。”故事最后女孩离开了,男孩贯着北风穿梭于人群里。

Pthreads && NSThread

预先来拘禁与线程有极度直白关乎之相同模拟C的API:

面前片总统就是不详细描述了,后面才是端正代码~

自家就带在淡淡惆怅可惜这不设人意的产物。几年后,我打下了姚非拉作《80℃》单行本,花了一致天时间看了,突然想起“100℃太沸,50℃太凉,80℃的痴情刚刚好。”虽然未思量确认,但确实是只所以然。

Pthreads

POSIX线程(POSIX
threads),简称Pthreads,是线程的POSIX标准。该规范定义了创办与操纵线程的身API。在类Unix操作系统(Unix、Linux、Mac
OS X等)中,都用Pthreads作为操作系统的线程。

第一来一个web.xml文件,这个属于异常布局文件,由于要写login,里面大概布置一下核心条件就可以

青春年华时总说校园恋爱青涩无知男女双方不知道爱情,如今才发觉校园内的相恋才真正纯真。朵朵是只天真可爱之大学生,与男朋友恋爱里被情敌挑战和男友的不体贴,面对心爱的男友,自卑而可爱之朵朵终于过在泥泞和男朋友和好如初。

伟上有木有,跨平台有木有,你从未因此过发木有!下面我们来拘禁一下夫类似牛逼但实在基本用非交的Pthreads举凡怎用之:

不如我们来为此Pthreads创造一个线程去实施一个职责:

记得引入头文件`#import "pthread.h"`

-(void)pthreadsDoTask{
    /*
     pthread_t:线程指针
     pthread_attr_t:线程属性
     pthread_mutex_t:互斥对象
     pthread_mutexattr_t:互斥属性对象
     pthread_cond_t:条件变量
     pthread_condattr_t:条件属性对象
     pthread_key_t:线程数据键
     pthread_rwlock_t:读写锁
     //
     pthread_create():创建一个线程
     pthread_exit():终止当前线程
     pthread_cancel():中断另外一个线程的运行
     pthread_join():阻塞当前的线程,直到另外一个线程运行结束
     pthread_attr_init():初始化线程的属性
     pthread_attr_setdetachstate():设置脱离状态的属性(决定这个线程在终止时是否可以被结合)
     pthread_attr_getdetachstate():获取脱离状态的属性
     pthread_attr_destroy():删除线程的属性
     pthread_kill():向线程发送一个信号
     pthread_equal(): 对两个线程的线程标识号进行比较
     pthread_detach(): 分离线程
     pthread_self(): 查询线程自身线程标识号
     //
     *创建线程
     int pthread_create(pthread_t _Nullable * _Nonnull __restrict, //指向新建线程标识符的指针
     const pthread_attr_t * _Nullable __restrict,  //设置线程属性。默认值NULL。
     void * _Nullable (* _Nonnull)(void * _Nullable),  //该线程运行函数的地址
     void * _Nullable __restrict);  //运行函数所需的参数
     *返回值:
     *若线程创建成功,则返回0
     *若线程创建失败,则返回出错编号
     */

    //
    pthread_t thread = NULL;
    NSString *params = @"Hello World";
    int result = pthread_create(&thread, NULL, threadTask, (__bridge void *)(params));
    result == 0 ? NSLog(@"creat thread success") : NSLog(@"creat thread failure");
    //设置子线程的状态设置为detached,则该线程运行结束后会自动释放所有资源
    pthread_detach(thread);
}

void *threadTask(void *params) {
    NSLog(@"%@ - %@", [NSThread currentThread], (__bridge NSString *)(params));
    return NULL;
}

出口结果:

ThreadDemo[1197:143578] creat thread success
ThreadDemo[1197:143649] <NSThread: 0x600000262e40>{number = 3, name = (null)} - Hello World

自打印结果来拘禁,该任务是当初开发的线程中执之,但是感觉用起超过不自己,很多东西需要团结管理,单单是职责队列以及线程生命周期的治本虽足足你头疼的,那尔写来的代码还能是措施也!其实用弃这套API很少用,是为我们来更好之挑:NSThread

 

年轻时无懂爱的波澜壮阔为何结局总是落下遗憾。佳佳扔下了志恒又失踪了,而志恒实现了歌手梦也到至了女对象。幸福之他们当今后会带来在哪些的心怀回忆就段爱情。

NSThread

什么呀,它面向对象,再失探访苹果提供的API,对比一下Pthreads,简单明了,人生好像又载了日光与想,我们事先来平等看一下系统提供给我们的API自然就掌握怎么用了,来来来,我给您注释一下哟:

@interface NSThread : NSObject
//当前线程
@property (class, readonly, strong) NSThread *currentThread;
//使用类方法创建线程执行任务
+ (void)detachNewThreadWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
//判断当前是否为多线程
+ (BOOL)isMultiThreaded;
//指定线程的线程参数,例如设置当前线程的断言处理器。
@property (readonly, retain) NSMutableDictionary *threadDictionary;
//当前线程暂停到某个时间
+ (void)sleepUntilDate:(NSDate *)date;
//当前线程暂停一段时间
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
//退出当前线程
+ (void)exit;
//当前线程优先级
+ (double)threadPriority;
//设置当前线程优先级
+ (BOOL)setThreadPriority:(double)p;
//指定线程对象优先级 0.0~1.0,默认值为0.5
@property double threadPriority NS_AVAILABLE(10_6, 4_0);
//服务质量
@property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);
//线程名称
@property (nullable, copy) NSString *name NS_AVAILABLE(10_5, 2_0);
//栈区大小
@property NSUInteger stackSize NS_AVAILABLE(10_5, 2_0);
//是否为主线程
@property (class, readonly) BOOL isMainThread NS_AVAILABLE(10_5, 2_0);
//获取主线程
@property (class, readonly, strong) NSThread *mainThread NS_AVAILABLE(10_5, 2_0);
//初始化
- (instancetype)init NS_AVAILABLE(10_5, 2_0) NS_DESIGNATED_INITIALIZER;
//实例方法初始化,需要再调用start方法
- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument NS_AVAILABLE(10_5, 2_0);
- (instancetype)initWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
//线程状态,正在执行
@property (readonly, getter=isExecuting) BOOL executing NS_AVAILABLE(10_5, 2_0);
//线程状态,正在完成
@property (readonly, getter=isFinished) BOOL finished NS_AVAILABLE(10_5, 2_0);
//线程状态,已经取消
@property (readonly, getter=isCancelled) BOOL cancelled NS_AVAILABLE(10_5, 2_0);
//取消,仅仅改变线程状态,并不能像exist一样真正的终止线程
- (void)cancel NS_AVAILABLE(10_5, 2_0);
//开始
- (void)start NS_AVAILABLE(10_5, 2_0);
//线程需要执行的代码,一般写子类的时候会用到
- (void)main NS_AVAILABLE(10_5, 2_0);
@end

另外,还有一个NSObject的分类,瞅一眼:
@interface NSObject (NSThreadPerformAdditions)
//隐式的创建并启动线程,并在指定的线程(主线程或子线程)上执行方法。
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array NS_AVAILABLE(10_5, 2_0);
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg NS_AVAILABLE(10_5, 2_0);
@end

地方的牵线您还看中为?小的救助您下充斥同张图纸,您瞧好:

-(void)creatBigImageView{
    self.bigImageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
    [self.view addSubview:_bigImageView];
    UIButton *startButton = [UIButton buttonWithType:UIButtonTypeSystem];
    startButton.frame = CGRectMake(0, 0, self.view.frame.size.width / 2, 50);
    startButton.backgroundColor = [UIColor grayColor];
    [startButton setTitle:@"开始加载" forState:UIControlStateNormal];
    [startButton addTarget:self action:@selector(loadImage) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:startButton];

    UIButton *jamButton = [UIButton buttonWithType:UIButtonTypeSystem];
    jamButton.frame = CGRectMake(self.view.frame.size.width / 2, 0, self.view.frame.size.width / 2, 50);
    jamButton.backgroundColor = [UIColor grayColor];
    [jamButton setTitle:@"阻塞测试" forState:UIControlStateNormal];
    [jamButton addTarget:self action:@selector(jamTest) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:jamButton];
}

-(void)jamTest{
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"线程阻塞" message:@"" delegate:nil cancelButtonTitle:@"好" otherButtonTitles:nil, nil];
    [alertView show];
}


-(void)loadImage{
    NSURL *imageUrl = [NSURL URLWithString:@"http://img5.duitang.com/uploads/item/201206/06/20120606174422_LZSeE.thumb.700_0.jpeg"];
    NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
    [self updateImageData:imageData];
}

-(void)updateImageData:(NSData*)imageData{
    UIImage *image = [UIImage imageWithData:imageData];
    self.bigImageView.image = image;
}

运行结果:

俺们可解的目,主线程阻塞了,用户不得以开展其它操作,你见了这样的应用也?
故此我们这么改一下:

-(void)creatBigImageView{
    self.bigImageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
    [self.view addSubview:_bigImageView];
    UIButton *startButton = [UIButton buttonWithType:UIButtonTypeSystem];
    startButton.frame = CGRectMake(0, 20, self.view.frame.size.width / 2, 50);
    startButton.backgroundColor = [UIColor grayColor];
    [startButton setTitle:@"开始加载" forState:UIControlStateNormal];
    [startButton addTarget:self action:@selector(loadImageWithMultiThread) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:startButton];

    UIButton *jamButton = [UIButton buttonWithType:UIButtonTypeSystem];
    jamButton.frame = CGRectMake(self.view.frame.size.width / 2, 20, self.view.frame.size.width / 2, 50);
    jamButton.backgroundColor = [UIColor grayColor];
    [jamButton setTitle:@"阻塞测试" forState:UIControlStateNormal];
    [jamButton addTarget:self action:@selector(jamTest) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:jamButton];
}

-(void)jamTest{
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"阻塞测试" message:@"" delegate:nil cancelButtonTitle:@"好" otherButtonTitles:nil, nil];
    [alertView show];
}

-(void)loadImageWithMultiThread{
    //方法1:使用对象方法
    //NSThread *thread=[[NSThread alloc]initWithTarget:self selector:@selector(loadImage) object:nil];
    //⚠️启动一个线程并非就一定立即执行,而是处于就绪状态,当CUP调度时才真正执行
    //[thread start];

    //方法2:使用类方法
    [NSThread detachNewThreadSelector:@selector(loadImage) toTarget:self withObject:nil];
}

-(void)loadImage{
    NSURL *imageUrl = [NSURL URLWithString:@"http://img5.duitang.com/uploads/item/201206/06/20120606174422_LZSeE.thumb.700_0.jpeg"];
    NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
    //必须在主线程更新UI,Object:代表调用方法的参数,不过只能传递一个参数(如果有多个参数请使用对象进行封装),waitUntilDone:是否线程任务完成执行
    [self performSelectorOnMainThread:@selector(updateImageData:) withObject:imageData waitUntilDone:YES];

    //[self updateImageData:imageData];
}


-(void)updateImageData:(NSData*)imageData{
    UIImage *image = [UIImage imageWithData:imageData];
    self.bigImageView.image = image;
}

运作结果:

好家伙呀,用几近线程果然能缓解线程阻塞的题材,并且NSThread也比Pthreads哼用,仿佛你针对会熟练使用多线程又产生矣一丝丝晨光。假如自己来不少不一品种的职责,每个任务中还有联系以及倚重,你是未是同时懵逼了,上面的而是匪是道以白看了,其实开被我觉着NSThread故此到最好多之虽是[NSThread currentThread];了。(不要慌,往下看…
…)


<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
     <servlet-name>springmvc</servlet-name>
     <url-pattern>/</url-pattern>
  </servlet-mapping>

诚实的孙甜甜中上了“什么还非决”的江海洋,那个酷暑,敢爱敢恨的孙小甜走上前了拥挤剧组,认识了江海洋,然而一连串的事有,当好好爱情中遇到现实,敢爱敢恨的孙甜甜但能够以遗憾里成长。

GCD

GCD,全名Grand Central Dispatch,中文名郭草地,是基于C语言的等同仿照多线程开发API,一听名字就是是只狠角色,也是现阶段苹果官方推荐的多线程开发方式。可以说凡是使用方便,又休失去逼格。总体来说,他解决我提到的地方直接操作线程带来的难题,它自动帮助您管理了线程的生命周期以及任务的实践规则。下面我们见面频之协商一个歌词,那就算是任务,说白了,任务事实上就是你要执行的那段代码

在的斯为Dispatcher
Servlet,可以依据servlet-name找到相应的略微布置文件,也即是布spring
MVC的文本

《80℃》是讲诉爱情故事的合集,每个单行本都是一个独立故事,从年轻到老年,不同年龄段对爱情之懂得以及经历给读者找到这好之背影,或感叹或哀愁或悲悯。都说爱情是玫瑰花,充满芬芳却枝节满是刺,从其萌芽都是忍在荆棘成长开花。

任务管理方——队列

方说当我们要保管几近单任务时,线程开发被我们带来了肯定的技术难度,或者说非方便性,GCD给来了我们统一管理职责的艺术,那就是班。我们来拘禁一下iOS基本上线程操作中的序列:(⚠️不管是串行还是并行,队列都是依照FIFO的基准依次触发任务)

以web.xml文件同级目录下新建springmvc-servlet.xml文件,下面是springmvc-servlet.xml文件被的情节

好的故事不用对取巧的,它的细枝末节会引领你会意故事本身。作者写时拿每面技术都分配平衡,拒绝了大量的本性色彩摄入,所作所为不过只是怀念找到能诵懂故事的口而已。

星星独通用队列:
  • 出错行队列:所有任务会当一如既往久线程中实践(有或是当前线程也产生或是新开发的线程),并且一个任务尽完毕后,才起来实行下一个任务。(等待完成)
  • 互相队列:可以开启多长达线程并行执行任务(但切莫肯定会被新的线程),并且当一个职责放到指定线程开始履行时,下一个职责就好开实施了。(等待发生)

 

姚非拉的故事是牵动在感情的,你看他的各级一格分镜每一样句语言都湿着情绪,不用作者亲身交代独白,对话吗是轻描淡写,你生出或就是以有同一眨眼尽管心领神会了感情温度。

星星单例外班:
  • 主队列:系统为我们创建好的一个串行队列,牛逼的处在当叫它管理须在主线程遭遇实施之职责,属于有劳保的。
  • 全局队列:系统啊咱创建好之一个互队列,使用起来与我们和好创造的互相队列无本质区别。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/mvc 
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
    <!--默认的注解映射的支持 -->
    <mvc:annotation-driven/>
    <!--启用自动扫描 -->
    <context:component-scan base-package="controller"/>
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

每当姚非拉笔下,立场感也异常死,对错是非从不会面世在姚非拉的著述里,也非偏袒角色,他只是做只道故事之丁,故事讲了就终止了,喜怒哀乐都无读者意会。

职责执行方

说了班,相应的,任务除了管理,还得执行,要不然有钱未费,掉了白,并且以GCD中并无能够一直开辟线程执行任务,所以在任务在队列之后,GCD给起了少种实施措施——同步执行(sync)和异步执行(async)。

  • 联合执行:在时线程执行任务,不见面开发新的线程。必须等交Block函数执行完毕后,dispatch函数才见面回到。
  • 异步执行:可以以新的线程中推行任务,但无必然会开发新的线程。dispatch函数会应声回去,
    然后Block在后台异步执行。

注意说明的凡,启动自动扫描,spring会在指定的包下(例如我这里是controller包),自动扫描标注@Controller的类似

 忽然想更一样集80℃的痴情,如温水一样,陪伴为细水流年。

点的这些理论都是本人在博受套路背后总出的血淋淋的经验,与君共享,但是如此形容自己猜测你势必还是免晓得,往下看,说不定有惊喜呢。

prefix指的是返的价值为电动加一个前缀,同理suffix指的饶是后缀


职责队列组合方式

深信这个标题你看罢无数蹩脚?是休是看了也未知道究竟怎么用?这么巧,我为是,请相信下面这些自然有您莫晓并且想如果之,我们由区区只极度直接的触及切入:

《80℃》

1. 线程死锁

这您是未是也扣罢许多不好?哈哈哈!你是休是道自家又如开复制黏贴了?请于生看:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"1========%@",[NSThread currentThread]);
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"2========%@",[NSThread currentThread]);
    });
    NSLog(@"3========%@",[NSThread currentThread]);
}

运作结果:

打印结果:

ThreadDemo[5615:874679] 1========<NSThread: 0x608000072440>{number = 1, name = main}

实在不是本身套路你,我们要得分析一下怎么会死锁,因为要为那些并未遭受过套路的民情里养一段落美好的追忆,分享代码,我们是当真的!

 

志恒和佳佳

事情是如此的:

咱先举行一个概念:- (void)viewDidLoad{} —> 任务A,GCD同步函数
—>任务B。
总而言之也,大概是如此的,首先,任务A于主队列,并且一度起实施,在主线程打印有1===... ...,然后这时任务B被投入到主队列中,并且一路实施,这尼玛事都蛮了,系统说,同步施行啊,那我莫起头新的线程了,任务B说自家要是等自身中的Block函数执行到位,要无我就不回,但是主队列说了,玩蛋去,我是串行的,你得等A执行完毕才能够轮至你,不克怪了规矩,同时,任务B作为任务A的内函数,必须等任务B执行完函数回才能够实施下一个任务。那就算导致了,任务A等任务B完成才能继续执行,但作为串行队列的主队列又不可知给任务B在任务A未得之前开始推行,所以任务A等着任务B完成,任务B等正任务A完成,等待,永久的等候。所以便死锁了。简单不?下面我们郑重看一下咱们不知不觉书写的代码!

 

2. 这么非杀锁

切莫设就描写个极度简便易行的:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"1========%@",[NSThread currentThread]);
    NSLog(@"2========%@",[NSThread currentThread]);
    NSLog(@"3========%@",[NSThread currentThread]);
}

打印结果:

ThreadDemo[5803:939324] 1========<NSThread: 0x600000078340>{number = 1, name = main}
ThreadDemo[5803:939324] 2========<NSThread: 0x600000078340>{number = 1, name = main}
ThreadDemo[5803:939324] 3========<NSThread: 0x600000078340>{number = 1, name = main}

事先有人提问:顺序打印,没毛病,全于主线程执行,而且顺序执行,那它们必然是在主队列同步执行之呀!那为何没有死锁?苹果之操作系统果然高深啊!

事实上这里来一个误区,那就是是任务在主线程顺序执行就是预示队列。其实某些涉还没,如果手上于主线程,同步执行任务,不管在什么队任务都是逐一执行。把有任务都盖异步执行的办法进入到主队列中,你见面发觉它为是逐一执行之。

深信不疑你懂点的死锁情况后,你一定会手贱改化这样试试:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"1========%@",[NSThread currentThread]);
    dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"2========%@",[NSThread currentThread]);
    });
    NSLog(@"3========%@",[NSThread currentThread]);
}

打印结果:

ThreadDemo[5830:947858] 1========<NSThread: 0x60000007bb80>{number = 1, name = main}
ThreadDemo[5830:947858] 2========<NSThread: 0x60000007bb80>{number = 1, name = main}
ThreadDemo[5830:947858] 3========<NSThread: 0x60000007bb80>{number = 1, name = main}

卿发觉正常执行了,并且是逐一执行之,你是未是如持有思念,没错,你想的同自家思念的凡同一的,和上诉情况亦然,任务A在主队列中,但是任务B加入到了大局队列,这时候,任务A以及任务B没有排的约束,所以任务B就优先执行喽,执行了后函数返回,任务A接着执行。

自身猜测你肯定手贱这么转了:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"1========%@",[NSThread currentThread]);
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"2========%@",[NSThread currentThread]);
    });
    NSLog(@"3========%@",[NSThread currentThread]);
}

打印结果:

ThreadDemo[5911:962470] 1========<NSThread: 0x600000072700>{number = 1, name = main}
ThreadDemo[5911:962470] 3========<NSThread: 0x600000072700>{number = 1, name = main}
ThreadDemo[5911:962470] 2========<NSThread: 0x600000072700>{number = 1, name = main}

周密而帅气的而一定发现不是逐一打印了,而且为不会见死锁,明明还是加到主队列里了什么,其实当任务A在履行时,任务B加入到了主队列,注意哦,是异步执行,所以dispatch函数不见面等到Block执行到位才回来,dispatch函数返回后,那任务A可以继续执行,Block任务我们可以认为于生一样帧顺序进入队列,并且默认无限下一致轴执行。这便是干什么而看看2===... ...大凡最终输出的了。(⚠️一个函数的出多独里面函数异步执行时,不会见招死锁的以,任务A执行完毕后,这些异步执行之中函数会顺序执行)。

观这里呢是够辛苦了,上面是受闹底完整目录,下面开始勾画逻辑代码,先从loginController开始

咱们说说队列与履行方的反衬

面说了系自带的片个序列,下面我们来之所以好创办的序列研究一下各种搭配情况。
我们事先创造两只队,并且测试方法都是在主线程中调用:

//串行队列
self.serialQueue = dispatch_queue_create("serialQueue.ys.com", DISPATCH_QUEUE_SERIAL);
//并行队列
self.concurrentQueue = dispatch_queue_create("concurrentQueue.ys.com", DISPATCH_QUEUE_CONCURRENT);
@Controller
public class LoginController {
    @RequestMapping(value="/",method=RequestMethod.GET)
    public String sayHello(){
        //model.addAttribute("msg", "Hello,World!");
        return "login";
    }
1. 串行队列 + 同步施行
-(void)queue_taskTest{
    dispatch_sync(self.serialQueue, ^{
        NSLog(@"1========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:1];
    });
    dispatch_sync(self.serialQueue, ^{
        NSLog(@"2========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:2];
    });
    dispatch_sync(self.serialQueue, ^{
        NSLog(@"3========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:3];
    });
    NSLog(@"4========%@",[NSThread currentThread]);
}

打印结果:

ThreadDemo[6735:1064390] 1========<NSThread: 0x600000073cc0>{number = 1, name = main}
ThreadDemo[6735:1064390] 2========<NSThread: 0x600000073cc0>{number = 1, name = main}
ThreadDemo[6735:1064390] 3========<NSThread: 0x600000073cc0>{number = 1, name = main}
ThreadDemo[6735:1064390] 4========<NSThread: 0x600000073cc0>{number = 1, name = main}

举且在当下线程顺序执行,也就是说,同步实施不有开发新线程的力。

分解上面代码,@Controller,标注此近乎是Controller类,spring会自动进行扫描,@Request
Mapping中的value指的是url中的地方后缀,设置成/的目的自然是为着便于啊,

2. 串行队列 + 异步执行
-(void)queue_taskTest{
    dispatch_async(self.serialQueue, ^{
        NSLog(@"1========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:1];
    });
    dispatch_async(self.serialQueue, ^{
        NSLog(@"2========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:2];
    });
    dispatch_async(self.serialQueue, ^{
        NSLog(@"3========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:3];
    });
    NSLog(@"4========%@",[NSThread currentThread]);
}

打印结果:

ThreadDemo[6774:1073235] 4========<NSThread: 0x60800006e9c0>{number = 1, name = main}
ThreadDemo[6774:1073290] 1========<NSThread: 0x608000077000>{number = 3, name = (null)}
ThreadDemo[6774:1073290] 2========<NSThread: 0x608000077000>{number = 3, name = (null)}
ThreadDemo[6774:1073290] 3========<NSThread: 0x608000077000>{number = 3, name = (null)}

先行打印了4,然后挨家挨户以子线程中打印1,2,3。说明异步执行有开发新线程的力量,并且串行队列必须顶及前面一个任务尽完毕才会起施行下一个任务,同时,异步执行会使中函数率先返回,不见面以及方实施的表面函数发生死锁。

遵启动工程时,url只需要输入什么localhost:8080/项目名为,它就会自行跳反到login页面;method指的是来之url是post请求还是get请求

3. 并行队列 + 同步施行
-(void)queue_taskTest{
    dispatch_sync(self.concurrentQueue, ^{
        NSLog(@"1========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:1];
    });
    dispatch_sync(self.concurrentQueue, ^{
        NSLog(@"2========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:2];
    });
    dispatch_sync(self.concurrentQueue, ^{
        NSLog(@"3========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:3];
    });
    NSLog(@"4========%@",[NSThread currentThread]);
}

运作结果:

ThreadDemo[7012:1113594] 1========<NSThread: 0x60800007e340>{number = 1, name = main}
ThreadDemo[7012:1113594] 2========<NSThread: 0x60800007e340>{number = 1, name = main}
ThreadDemo[7012:1113594] 3========<NSThread: 0x60800007e340>{number = 1, name = main}
ThreadDemo[7012:1113594] 4========<NSThread: 0x60800007e340>{number = 1, name = main}

免被新的线程执行任务,并且Block函数执行好后dispatch函数才见面回来,才能够连续朝着下实施,所以我们看出的结果是各个打印的。

return的凡login字符串,大家还记上面说之prefix了咔嚓,它就是会见拿您的url自动拼接上,完整路径就是是下边这个

4. 连行队列 + 异步执行
-(void)queue_taskTest{
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"1========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:1];
    });
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"2========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:2];
    });
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"3========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:3];
    });
    NSLog(@"4========%@",[NSThread currentThread]);
}

打印结果:

ThreadDemo[7042:1117492] 1========<NSThread: 0x600000071900>{number = 3, name = (null)}
ThreadDemo[7042:1117491] 3========<NSThread: 0x608000070240>{number = 5, name = (null)}
ThreadDemo[7042:1117451] 4========<NSThread: 0x600000067400>{number = 1, name = main}
ThreadDemo[7042:1117494] 2========<NSThread: 0x600000071880>{number = 4, name = (null)}

开发了差不多个线程,触发任务的会是逐一的,但是咱看到完成任务的年华可是轻易的,这取决CPU对于不同线程的调度分配,但是,线程不是白无限开拓的,当任务量足够好时,线程是会还用的。

/WEB-INF/jsp/login.jsp

扛一下重中之重啊

 接下来看login.jsp

1. 对此单核CPU来说,不存在真正意义及之互相,所以,多线程执行任务,其实也止是一个人数在干活,CPU的调度控制了非等待任务的实践速率,同时对于非等待任务,多线程并不曾真正含义提高效率。
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>login</title>
</head>
<body>
    <form action="login" method="post">
        用户名:<input type="text" name="username"/><br/>
        密&nbsp;&nbsp;码:<input type="password" name="password"/>
        <input type="submit" value="登陆"/>
        <a href="regist">注册</a>
    </form>
</body>
</html>
2. 线程可以简单的以为即便是平截代码+运行时数。

此处的action返回的凡login,Controller会自动捕获到这请,于是当login
Controller中使发一个方来捕获这个请

3. 旅施行会以当下线程执行任务,不备开发线程的能力或说没有必要开辟新的线程。并且,同步执行要顶交Block函数执行了,dispatch函数才见面返回,从而阻塞同一拧行队列中外部方法的履行。
@RequestMapping(value="login",method=RequestMethod.POST)
    public String login(Model model, // 向前台页面传的值放入model中
            HttpServletRequest request){ // 从前台页面取得的值
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String user_name = LoginCheck.check(username, password);
        if(user_name != null && user_name != ""){
            model.addAttribute("msg", user_name);
            return "success";
        }else{
            return "login2";
        }
    }
4. 异步执行dispatch函数会一直归,Block函数我们好看其见面以产一致轴加入队列,并根据所在队列目前之天职状态太下一致轴执行,从而不会见卡住时外部任务的实施。同时,只有异步执行才发生开拓新线程的必需,但是异步执行不肯定会开发新线程。

登陆嘛,当然要来证,于是就产生矣LoginCheck,不多说,上代码

5. 一旦是排,肯定是FIFO(先进先出),但是谁先实行完要看第1条。
package logic;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import dao.Dao;

public class LoginCheck {

    public static String check(String username,String password){
        try {
            Connection conn = Dao.getConnection();
            PreparedStatement p = conn.prepareStatement("select * from user_t where user_name=? and password=?");
            p.setString(1, username);
            p.setString(2, password);
            ResultSet rs = p.executeQuery();
            if(rs.next()){
                String user_name = rs.getString("user_name");
                Dao.close(rs, p, conn);
                return user_name;
            }
            Dao.close(rs, p, conn);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
}
6. 要是是串行队列,肯定要等达标一个职责履行就,才会起产一个职责。但是彼此队列当及一个任务开始执行后,下一个任务便可初步实施。

通向数据库查询就要有DAO啦,Dao网上还发生,我的哪怕是以网上随便找找一个修改就因此了~

7. 怀念如果开辟新线程必须让任务在异步执行,想使开拓多个线程,只有吃任务在交互队列中异步执行才得以。执行措施及排类型多层结在得水平达到能落实对代码执行顺序的调度。
package dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Dao {
    // 获取数据库连接
    public static Connection getConnection(){

        Connection conn = null;
        String url = "jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=Hongkong";
        try
        {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(url,"root","数据库密码");//大家分享代码的时候也不要暴露自己的数据库密码,这样是非常不安全的
        }
        catch(ClassNotFoundException e)
        {
            e.printStackTrace();
            System.out.println("数据库驱动加载出错");
        }
        catch(SQLException e)
        {
            e.printStackTrace();
            System.out.println("数据库出错");
        }
        return conn;
    }
     //关闭相关通道
    public static void close(ResultSet rs,PreparedStatement p,Connection conn)
    {
        try
        {
            if(!rs.isClosed()){
                rs.close();
            }
            if(!p.isClosed()){
                p.close();
            }
            if(!conn.isClosed()){
                conn.close();
            }
        }
        catch(SQLException e)
        {
            e.printStackTrace();
            System.out.println("数据关闭出错");
        }
    }
    //关闭相关通道
    public static void close(PreparedStatement p,Connection conn)
    {
        try
        {
            if(!p.isClosed()){
                p.close();
            }
            if(!conn.isClosed()){
                conn.close();
            }
        }
        catch(SQLException e)
        {
            e.printStackTrace();
            System.out.println("数据关闭出错");
        }
    }
}
8. 合伙+串行:未开发新线程,串行执行任务;同步+并行:未开发新线程,串行执行任务;异步+串行:新开辟一长条线程,串行执行任务;异步+并行:开辟多漫长新线程,并行执行任务;在主线程遭遇一道运用主队列执行任务,会导致死锁。

好了,如果查询的结果相当上数据库中查询到的价了,那么就算可过反至success页面了,success.jsp

8. 于多核CPU来说,线程数量也未可知顶开拓,线程的开拓同样会消耗资源,过多线程同时处理任务并无是你想像受之人头大多力充分。
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登陆成功</title>
</head>
<body>
    登陆成功!
    欢迎~${msg};
</body>
</html>

GCD其他函数用法

login大功告成,接下的注册页面和此道理相似,我非多废话了,把代码附上供大家参考

1. dispatch_after

该函数用于任务延时执行,其中参数dispatch_time_t表示延时时长,dispatch_queue_t意味着采取谁队。如果队列未主队列,那么任务在主线程执行,如果帮列为全局队列或者自己创造的队,那么任务在子线程执行,代码如下:

-(void)GCDDelay{
    //主队列延时
    dispatch_time_t when_main = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC));
    dispatch_after(when_main, dispatch_get_main_queue(), ^{
        NSLog(@"main_%@",[NSThread currentThread]);
    });
    //全局队列延时
    dispatch_time_t when_global = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4.0 * NSEC_PER_SEC));
    dispatch_after(when_global, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"global_%@",[NSThread currentThread]);
    });
    //自定义队列延时
    dispatch_time_t when_custom = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC));
    dispatch_after(when_custom, self.serialQueue, ^{
        NSLog(@"custom_%@",[NSThread currentThread]);
    });
}

打印结果:

ThreadDemo[1508:499647] main_<NSThread: 0x60000007cf40>{number = 1, name = main}
ThreadDemo[1508:499697] global_<NSThread: 0x608000262d80>{number = 3, name = (null)}
ThreadDemo[1508:499697] custom_<NSThread: 0x608000262d80>{number = 3, name = (null)}

首先是regist.jsp

2. dispatch_once

管函数在普生命周期内仅会履行同一不良,看代码。

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"%@",[NSThread currentThread]);
    });
}

打印结果:

ThreadDemo[1524:509261] <NSThread: 0x600000262940>{number = 1, name = main}
无论你怎么疯狂的点击,在第一次打印之后,输出台便岿然不动。
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>注册页面</title>
</head>
<body>
    <form action="registSuccess" method="Post">
        用户名:<input type="text" name="username"/>
        密&nbsp;&nbsp;码<input type="text" name="password"/>
        年&nbsp;&nbsp;龄<input type="number" name="age"/>
        <input type="submit" value="提交"/>
    </form>
</body>
</html>
3. dispatch_group_async & dispatch_group_notify

试想,现在牛逼的您只要现在个别摆设小图,并且你如果对等片摆图都生充斥完成后将她们并起来,你要怎么开?我从不怕非见面管有限摆图并成一摆放图什么,牛逼的自家怎么可能发这种想法啊?

实质上方法有多,比如您可同样摆设同摆下载,再遵照采用有变量和Blcok实现计数,但是既然今天咱们叙到当时,那我们不怕得合乎乡随俗,用GCD来落实,有一个神器的物叫做队列组,当进入到队列组中的有着任务履行好之后,会调用dispatch_group_notify函数通知任务尽好,代码如下:

-(void)GCDGroup{
    //
    [self jointImageView];
    //
    dispatch_group_t group = dispatch_group_create();
    __block UIImage *image_1 = nil;
    __block UIImage *image_2 = nil;
    //在group中添加一个任务
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        image_1 = [self imageWithPath:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1502706256731&di=371f5fd17184944d7e2b594142cd7061&imgtype=0&src=http%3A%2F%2Fimg4.duitang.com%2Fuploads%2Fitem%2F201605%2F14%2F20160514165210_LRCji.jpeg"];

    });
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        image_2 = [self imageWithPath:@"https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=776127947,2002573948&fm=26&gp=0.jpg"];
    });
    //group中所有任务执行完毕,通知该方法执行
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        self.imageView_1.image = image_1;
        self.imageView_2.image = image_2;
        //
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 100), NO, 0.0f);
        [image_2 drawInRect:CGRectMake(0, 0, 100, 100)];
        [image_1 drawInRect:CGRectMake(100, 0, 100, 100)];
        UIImage *image_3 = UIGraphicsGetImageFromCurrentImageContext();
        self.imageView_3.image = image_3;
        UIGraphicsEndImageContext();
    });
}

-(void)jointImageView{
    self.imageView_1 = [[UIImageView alloc] initWithFrame:CGRectMake(20, 50, 100, 100)];
    [self.view addSubview:_imageView_1];

    self.imageView_2 = [[UIImageView alloc] initWithFrame:CGRectMake(140, 50, 100, 100)];
    [self.view addSubview:_imageView_2];

    self.imageView_3 = [[UIImageView alloc] initWithFrame:CGRectMake(20, 200, 200, 100)];
    [self.view addSubview:_imageView_3];

    self.imageView_1.layer.borderColor = self.imageView_2.layer.borderColor = self.imageView_3.layer.borderColor = [UIColor grayColor].CGColor;
    self.imageView_1.layer.borderWidth = self.imageView_2.layer.borderWidth = self.imageView_3.layer.borderWidth = 1;
}

对接下是RegistController

4. dispatch_barrier_async

栅栏函数,这么看来她亦可挡住或者分隔什么事物,别瞎猜了,反正你同时怀疑不针对,看就,使用是道创建的天职,会招来当前排中生出没来其他任务而尽,如果发生,则等待都产生任务履行了后再行实施,同时,在此任务后进入队列的职责,需要拭目以待这任务尽得后,才会实施。看代码,老铁。(⚠️
这里连作班必须是投机创建的。如果选择全局队列,这个函数和dispatch_async将见面没有差异。)

-(void)GCDbarrier{

    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"任务1");
    });
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"任务2");
    });

//    dispatch_barrier_async(self.concurrentQueue, ^{
//        NSLog(@"任务barrier");
//    });

//    NSLog(@"big");
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"任务3");
    });
//    NSLog(@"apple");
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"任务4");
    });
}

运行结果:

ThreadDemo[1816:673351] 任务3
ThreadDemo[1816:673353] 任务1
ThreadDemo[1816:673350] 任务2
ThreadDemo[1816:673370] 任务4

举凡匪是如你所预期,牛逼大了,下面我们开辟第一句注释:

-(void)GCDbarrier{

    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"任务1");
    });
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"任务2");
    });

    dispatch_barrier_async(self.concurrentQueue, ^{
        NSLog(@"任务barrier");
    });

//    NSLog(@"big");
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"任务3");
    });
//    NSLog(@"apple");
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"任务4");
    });
}

打印结果:

ThreadDemo[1833:678739] 任务2
ThreadDemo[1833:678740] 任务1
ThreadDemo[1833:678740] 任务barrier
ThreadDemo[1833:678740] 任务3
ThreadDemo[1833:678739] 任务4

这个结果跟咱们地方的分解到契合,我们可大概的操纵函数执行的顺序了,你离开大牛又守了相同步,如果今天之君切莫见面存疑还有dispatch_barrier_sync这函数的言语,说明…
…嘿嘿嘿,我们看一下是函数和点我们所以到的函数的分,你必想到了,再打开第二个跟老三单注释,如下:

-(void)GCDbarrier{

    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"任务1");
    });
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"任务2");
    });

    dispatch_barrier_async(self.concurrentQueue, ^{
        NSLog(@"任务barrier");
    });

    NSLog(@"big");
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"任务3");
    });
    NSLog(@"apple");
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"任务4");
    });
}

运行结果:

ThreadDemo[1853:692434] 任务1
ThreadDemo[1853:692421] 任务2
ThreadDemo[1853:692387] big
ThreadDemo[1853:692421] 任务barrier
ThreadDemo[1853:692387] apple
ThreadDemo[1853:692421] 任务3
ThreadDemo[1853:692434] 任务4

决不焦躁,我们转移一下函数:

-(void)GCDbarrier{

    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"任务1");
    });
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"任务2");
    });

    dispatch_barrier_sync(self.concurrentQueue, ^{
        NSLog(@"任务barrier");
    });

    NSLog(@"big");
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"任务3");
    });
    NSLog(@"apple");
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"任务4");
    });
}

打印结果:

ThreadDemo[1874:711841] 任务1
ThreadDemo[1874:711828] 任务2
ThreadDemo[1874:711793] 任务barrier
ThreadDemo[1874:711793] big
ThreadDemo[1874:711793] apple
ThreadDemo[1874:711828] 任务3
ThreadDemo[1874:711841] 任务4

老铁,发现了也?这简单只函数对于队列的栅栏作用是同的,但是对于该函数相对于其它中间函数遵循了极其初步说到之一头同异步的平整。你是不是发硌懵逼,如果你蒙蔽了,那么请以列一个输出后面打印出当下的线程,如果你要么懵逼,那么请而再看,有劳动,不谢!

package controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import logic.RegistCheck;

@Controller
public class RegistController {
    @RequestMapping(value="regist",method=RequestMethod.GET)
    public String regist(){
        return "regist";
    }

    @RequestMapping(value="registSuccess",method=RequestMethod.POST)
    public String registSuccess(HttpServletRequest request,Model model){
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String age = request.getParameter("age");

        if(RegistCheck.registCheck(username, password,age)){
            model.addAttribute("username", username);
            return "login";
        }else{
            return "regist2";
        }
    }
}
5. dispatch_apply

欠函数用于更执行有任务,如果任务队列是并行队列,重复执行之天职会连作执行,如果任务队列为失误行队列,则任务会挨个执行,需要注意的凡,该函数为一起函数,要防范线程阻塞与死锁哦,老铁。

通下是RegistCheck

阴差阳错行队列:
-(void)GCDApply{
    //重复执行
    dispatch_apply(5, self.serialQueue, ^(size_t i) {
        NSLog(@"第%@次_%@",@(i),[NSThread currentThread]);
    });
}

运作结果:

ThreadDemo[1446:158101] 第0次_<NSThread: 0x600000079ac0>{number = 1, name = main}
ThreadDemo[1446:158101] 第1次_<NSThread: 0x600000079ac0>{number = 1, name = main}
ThreadDemo[1446:158101] 第2次_<NSThread: 0x600000079ac0>{number = 1, name = main}
ThreadDemo[1446:158101] 第3次_<NSThread: 0x600000079ac0>{number = 1, name = main}
ThreadDemo[1446:158101] 第4次_<NSThread: 0x600000079ac0>{number = 1, name = main}

 

交互队列:
-(void)GCDApply{
    //重复执行
    dispatch_apply(5, self.concurrentQueue, ^(size_t i) {
        NSLog(@"第%@次_%@",@(i),[NSThread currentThread]);
    });
}

运行结果:

ThreadDemo[1461:160567] 第2次_<NSThread: 0x608000076000>{number = 4, name = (null)}
ThreadDemo[1461:160534] 第0次_<NSThread: 0x60800006d8c0>{number = 1, name = main}
ThreadDemo[1461:160566] 第3次_<NSThread: 0x60000007d480>{number = 5, name = (null)}
ThreadDemo[1461:160569] 第1次_<NSThread: 0x60000007d440>{number = 3, name = (null)}
ThreadDemo[1461:160567] 第4次_<NSThread: 0x608000076000>{number = 4, name = (null)}
package logic;

import java.sql.Connection;
import java.sql.PreparedStatement;

import dao.Dao;

public class RegistCheck {

    public static boolean registCheck(String username,String password,String age){
        String user_name = LoginCheck.check(username, password);
        if(user_name == null || user_name == ""){
            try {
                Connection conn = Dao.getConnection();
                PreparedStatement p = conn.prepareStatement("insert user_t(user_name,password,age) VALUES (?,?,?);");
                p.setString(1, username);
                p.setString(2, password);
                p.setString(3, age);
                p.executeUpdate();
                System.out.println("注册成功");
                Dao.close(p, conn);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return false;
    }
}
死锁:
-(void)GCDApply{
    //重复执行
    dispatch_apply(5, dispatch_get_main_queue(), ^(size_t i) {
        NSLog(@"第%@次_%@",@(i),[NSThread currentThread]);
    });
}

运作结果:

再有一个registSuccess.jsp,成功返回的页面,我只是放了单空页面,没内容

6. dispatch_semaphore_create & dispatch_semaphore_signal & dispatch_semaphore_wait

在押就几乎独函数的时段你待抛开队列,丢掉同步异步,不要将她想到一起,混为一谈,信号量只是控制任务履行的一个谱而已,相对于面通过队以及实施措施来支配线程的开拓和天职的尽,它再也近对于任务一直的支配。类似于仅个队的无限要命并发数的控制机制,提高并行效率的还要,也戒太多线程的开拓对CPU早层负面的效率负担。
dispatch_semaphore_create创建信号量,初始值未能够小于0;
dispatch_semaphore_wait等降低信号量,也即是信号量-1;
dispatch_semaphore_signal增进信号量,也就算是信号量+1;
dispatch_semaphore_waitdispatch_semaphore_signal习以为常配对用。
关押一下代码吧,老铁。

-(void)GCDSemaphore{
    //
    //dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    dispatch_apply(5, self.concurrentQueue, ^(size_t i) {
        //dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_async(self.concurrentQueue, ^{
            NSLog(@"第%@次_%@",@(i),[NSThread currentThread]);
            //dispatch_semaphore_signal(semaphore);
        });
    });
}

若能猜测到运行结果为?没错,就是你想的这么,开辟了5只线程执行任务。

ThreadDemo[1970:506692] 第0次_<NSThread: 0x600000070f00>{number = 3, name = (null)}
ThreadDemo[1970:506711] 第1次_<NSThread: 0x6000000711c0>{number = 4, name = (null)}
ThreadDemo[1970:506713] 第2次_<NSThread: 0x6000000713c0>{number = 5, name = (null)}
ThreadDemo[1970:506691] 第3次_<NSThread: 0x600000070f40>{number = 6, name = (null)}
ThreadDemo[1970:506694] 第4次_<NSThread: 0x600000070440>{number = 7, name = (null)}

生一样步而一定猜到了,把注释的代码打开:

-(void)GCDSemaphore{
    //
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    dispatch_apply(5, self.concurrentQueue, ^(size_t i) {
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_async(self.concurrentQueue, ^{
            NSLog(@"第%@次_%@",@(i),[NSThread currentThread]);
            dispatch_semaphore_signal(semaphore);
        });
    });
}

运作结果:

ThreadDemo[2020:513651] 第0次_<NSThread: 0x608000073900>{number = 3, name = (null)}
ThreadDemo[2020:513651] 第1次_<NSThread: 0x608000073900>{number = 3, name = (null)}
ThreadDemo[2020:513651] 第2次_<NSThread: 0x608000073900>{number = 3, name = (null)}
ThreadDemo[2020:513651] 第3次_<NSThread: 0x608000073900>{number = 3, name = (null)}
ThreadDemo[2020:513651] 第4次_<NSThread: 0x608000073900>{number = 3, name = (null)}

异常鲜明,我起说之是本着之,哈哈哈哈,信号量是决定任务尽之严重性标准,当信号量为0时,所有任务等待,信号量越老,允许而并行执行的职责数进一步多。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>注册成功</title>
</head>
<body>
    注册成功!
</body>
</html>
GCD就先说到当时,很多API没有关联到,有趣味之校友等得以友善去看看,重要的凡法以及习惯,而不是您看了多少。

吓了,现在结束login和报页面都勾好了,新人刚到商家之时段非常容易碰到这么的略微练,哈哈哈说基本上矣,喜欢就点赞哈

NSOperation && NSOperationQueue

如若上面的郭草地假若您学会了,那么就片单东西而呢非自然能够模拟得会!

NSOperation以及NSOperationQueue举凡苹果对于GCD的包,其中也,NSOperation实在就是是咱地方所说的任务,但是这个仿佛非克直接以,我们只要就此外的点滴单子类,NSBlockOperationNSInvocationOperation,而NSOperationQueue也,其实就是接近于GCD中之班,用于管理而参加到内的任务。

迎转载,转载请注明出处~

NSOperation

它提供了有关任务之履行,取消,以及天天取任务之状态,添加任务依赖与优先级等方法与总体性,相对于GCD提供的方吧,更直观,更有利于,并且提供了重多的支配接口。(很多早晚,苹果设计之架是好过硬的,不要只是于乎他促成了哟,可能你拟到的物会另行多,一不小心又吹牛逼了,哦呵呵),有几个方式和属性我们询问一下:

@interface NSOperation : NSObject {
@private
    id _private;
    int32_t _private1;
#if __LP64__
    int32_t _private1b;
#endif
}

- (void)start;//启动任务 默认在当前线程执行
- (void)main;//自定义NSOperation,写一个子类,重写这个方法,在这个方法里面添加需要执行的操作。

@property (readonly, getter=isCancelled) BOOL cancelled;//是否已经取消,只读
- (void)cancel;//取消任务

@property (readonly, getter=isExecuting) BOOL executing;//正在执行,只读
@property (readonly, getter=isFinished) BOOL finished;//执行结束,只读
@property (readonly, getter=isConcurrent) BOOL concurrent; // To be deprecated; use and override 'asynchronous' below
@property (readonly, getter=isAsynchronous) BOOL asynchronous NS_AVAILABLE(10_8, 7_0);//是否并发,只读
@property (readonly, getter=isReady) BOOL ready;//准备执行

- (void)addDependency:(NSOperation *)op;//添加依赖
- (void)removeDependency:(NSOperation *)op;//移除依赖

@property (readonly, copy) NSArray<NSOperation *> *dependencies;//所有依赖关系,只读

typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
    NSOperationQueuePriorityVeryLow = -8L,
    NSOperationQueuePriorityLow = -4L,
    NSOperationQueuePriorityNormal = 0,
    NSOperationQueuePriorityHigh = 4,
    NSOperationQueuePriorityVeryHigh = 8
};//系统提供的优先级关系枚举

@property NSOperationQueuePriority queuePriority;//执行优先级

@property (nullable, copy) void (^completionBlock)(void) NS_AVAILABLE(10_6, 4_0);//任务执行完成之后的回调

- (void)waitUntilFinished NS_AVAILABLE(10_6, 4_0);//阻塞当前线程,等到某个operation执行完毕。

@property double threadPriority NS_DEPRECATED(10_6, 10_10, 4_0, 8_0);//已废弃,用qualityOfService替代。

@property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);//服务质量,一个高质量的服务就意味着更多的资源得以提供来更快的完成操作。

@property (nullable, copy) NSString *name NS_AVAILABLE(10_10, 8_0);//任务名称

@end

然而NSOperation本身是个抽象类,不能够直接利用,我们发出三栽艺术赋予它新的人命,就是底下就三单东西,您坐稳看好。

Java从上学及放弃,MySQL从删库到跑路,哈哈哈

NSOperation自定义子类

当即是自家只要说之第一单任务项目,我们得自定义继承给NSOperation的子类,并再次写父类提供的措施,实现一波拥有特种意义的职责。比如我们去下载一个图:

.h
#import <UIKit/UIKit.h>

@protocol YSImageDownLoadOperationDelegate <NSObject>
-(void)YSImageDownLoadFinished:(UIImage*)image;

@end

@interface YSImageDownLoadOperation : NSOperation

-(id)initOperationWithUrl:(NSURL*)imageUrl delegate:(id<YSImageDownLoadOperationDelegate>)delegate;

@end

.m
#import "YSImageDownLoadOperation.h"

@implementation YSImageDownLoadOperation{
    NSURL *_imageUrl;
    id _delegate;
}

-(id)initOperationWithUrl:(NSURL*)imageUrl delegate:(id<YSImageDownLoadOperationDelegate>)delegate{
    if (self == [super init]) {
        _imageUrl = imageUrl;
        _delegate = delegate;
    }
    return self;
}

-(void)main{
    @autoreleasepool {
        UIImage *image = [self imageWithUrl:_imageUrl];
        if (_delegate && [_delegate respondsToSelector:@selector(YSImageDownLoadFinished:)]) {
            [_delegate YSImageDownLoadFinished:image];
        }
    }
}

-(UIImage*)imageWithUrl:(NSURL*)url{
    NSData *imageData = [NSData dataWithContentsOfURL:url];
    UIImage *image = [UIImage imageWithData:imageData];
    return image;
}


@end

然后调用:
-(void)YSDownLoadImageOperationRun{
    YSImageDownLoadOperation *ysOper = [[YSImageDownLoadOperation alloc] initOperationWithUrl:[NSURL URLWithString:@"http://img5.duitang.com/uploads/item/201206/06/20120606174422_LZSeE.thumb.700_0.jpeg"] delegate:self];
    [ysOper start];
}

-(void)YSImageDownLoadFinished:(UIImage *)image{
    NSLog(@"%@",image);
}

运作打印结果:

ThreadDemo[4141:1100329] <UIImage: 0x60800009f630>, {700, 1050}

嗯呵呵,其实从定义之天职重新兼具指向性,它可满足你一定的求,但是一般用之于少,不晓凡是盖我太菜还是确实有众多更便民的措施和笔触实现如此的逻辑。

 

NSBlockOperation

其次个,就是网提供的NSOperation的子类NSBlockOperation,我们看一下外提供的API:

@interface NSBlockOperation : NSOperation {
@private
    id _private2;
    void *_reserved2;
}

+ (instancetype)blockOperationWithBlock:(void (^)(void))block;

- (void)addExecutionBlock:(void (^)(void))block;
@property (readonly, copy) NSArray<void (^)(void)> *executionBlocks;

@end

死简短,就即刻几乎只,我们就就此其实现一个职责:

-(void)NSBlockOperationRun{
    NSBlockOperation *blockOper = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"NSBlockOperationRun_%@_%@",[NSOperationQueue currentQueue],[NSThread currentThread]);
    }];
    [blockOper start];
}

运行结果:

ThreadDemo[4313:1121900] NSBlockOperationRun_<NSOperationQueue: 0x608000037420>{name = 'NSOperationQueue Main Queue'}_<NSThread: 0x60000006dd80>{number = 1, name = main}

咱俩发现这任务是当目前线程顺序执行之,我们发现还发出一个方法addExecutionBlock:试一下:

-(void)NSBlockOperationRun{
    NSBlockOperation *blockOper = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"NSBlockOperationRun_1_%@",[NSThread currentThread]);
    }];
    [blockOper addExecutionBlock:^{
        NSLog(@"NSBlockOperationRun_2_%@",[NSThread currentThread]);
    }];
    [blockOper addExecutionBlock:^{
        NSLog(@"NSBlockOperationRun_3_%@",[NSThread currentThread]);
    }];
    [blockOper addExecutionBlock:^{
        NSLog(@"NSBlockOperationRun_4_%@",[NSThread currentThread]);
    }];
    [blockOper start];
}

打印结果:

ThreadDemo[4516:1169835] NSBlockOperationRun_1_<NSThread: 0x60000006d880>{number = 1, name = main}
ThreadDemo[4516:1169875] NSBlockOperationRun_3_<NSThread: 0x600000070800>{number = 4, name = (null)}
ThreadDemo[4516:1169877] NSBlockOperationRun_4_<NSThread: 0x6080000762c0>{number = 5, name = (null)}
ThreadDemo[4516:1169893] NSBlockOperationRun_2_<NSThread: 0x608000076100>{number = 3, name = (null)}

于打印结果来拘禁,这个4单任务是异步并发执行之,开辟了大半长线程。

NSInvocationOperation

老三只,就是她了,同样为是网提供给咱们的一个职责类,基于一个target对象和一个selector来创造任务,具体代码:

-(void)NSInvocationOperationRun{
    NSInvocationOperation *invocationOper = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperSel) object:nil];
    [invocationOper start];
}
-(void)invocationOperSel{
    NSLog(@"NSInvocationOperationRun_%@",[NSThread currentThread]);
}

运转结果:

ThreadDemo[4538:1173118] NSInvocationOperationRun_<NSThread: 0x60800006e900>{number = 1, name = main}

运行结果以及NSBlockOperation单个block函数的履行办法同,同步顺序执行。的确系统的包装给予我们关于任务重直观的事物,但是对多只任务的控制机制并无圆满,所以我们发出求下一样个,也许你会眼前一亮。

NSOperationQueue

方说道我们创建的NSOperation职责目标好由此start方法来执行,同样我们好把这个职责目标上加至一个NSOperationQueue对象中去实践,好想念闹好东西,先看一下系的API:

@interface NSOperationQueue : NSObject {
@private
    id _private;
    void *_reserved;
}

- (void)addOperation:(NSOperation *)op;//添加任务
- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait NS_AVAILABLE(10_6, 4_0);//添加一组任务

- (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);//添加一个block形式的任务

@property (readonly, copy) NSArray<__kindof NSOperation *> *operations;//队列中所有的任务数组
@property (readonly) NSUInteger operationCount NS_AVAILABLE(10_6, 4_0);//队列中的任务数

@property NSInteger maxConcurrentOperationCount;//最大并发数

@property (getter=isSuspended) BOOL suspended;//暂停

@property (nullable, copy) NSString *name NS_AVAILABLE(10_6, 4_0);//名称

@property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);//服务质量,一个高质量的服务就意味着更多的资源得以提供来更快的完成操作。

@property (nullable, assign /* actually retain */) dispatch_queue_t underlyingQueue NS_AVAILABLE(10_10, 8_0);

- (void)cancelAllOperations;//取消队列中的所有任务

- (void)waitUntilAllOperationsAreFinished;//阻塞当前线程,等到队列中的任务全部执行完毕。

#if FOUNDATION_SWIFT_SDK_EPOCH_AT_LEAST(8)
@property (class, readonly, strong, nullable) NSOperationQueue *currentQueue NS_AVAILABLE(10_6, 4_0);//获取当前队列
@property (class, readonly, strong) NSOperationQueue *mainQueue NS_AVAILABLE(10_6, 4_0);//获取主队列
#endif

@end

来同样段子代码开心开心:

-(void)NSOperationQueueRun{
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    NSInvocationOperation *invocationOper = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperSel) object:nil];
    [queue addOperation:invocationOper];
    NSBlockOperation *blockOper = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"NSBlockOperationRun_%@",[NSThread currentThread]);
    }];
    [queue addOperation:blockOper];
    [queue addOperationWithBlock:^{
        NSLog(@"QUEUEBlockOperationRun_%@",[NSThread currentThread]);
    }];
}

打印结果:

ThreadDemo[4761:1205689] NSBlockOperationRun_<NSThread: 0x600000264480>{number = 4, name = (null)}
ThreadDemo[4761:1205691] NSInvocationOperationRun_<NSThread: 0x600000264380>{number = 3, name = (null)}
ThreadDemo[4761:1205706] QUEUEBlockOperationRun_<NSThread: 0x6000002645c0>{number = 5, name = (null)}

咱们发现,加入队列之后并非调用任务之start方,队列会拉扯您管理职责的履行情况。上诉执行结果说明这些职责在列中呢出现执行之。

下我们转移一下任务的预级:
invocationOper.queuePriority = NSOperationQueuePriorityVeryLow;

运转结果:

ThreadDemo[4894:1218440] QUEUEBlockOperationRun_<NSThread: 0x608000268880>{number = 3, name = (null)}
ThreadDemo[4894:1218442] NSBlockOperationRun_<NSThread: 0x60000026d340>{number = 4, name = (null)}
ThreadDemo[4894:1218457] NSInvocationOperationRun_<NSThread: 0x60000026d400>{number = 5, name = (null)}

俺们发现优先级低的职责会后执行,但是,这并无是纯属的,还有众多事物好左右CPU分配,以及操作系统对于任务以及线程的支配,只能说,优先级会于自然水准上让优先级赛之职责开始执行。同时,优先级只对同一队列中的任务使得哦。下面我们虽扣留一个会面忽视优先级的情形。

增长依靠关系
-(void)NSOperationQueueRun{
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    NSBlockOperation *blockOper_1 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 1000; i++) {
            NSLog(@"blockOper_1_%@_%@",@(i),[NSThread currentThread]);
        }
    }];

    NSBlockOperation *blockOper_2 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 1000; i++) {
            NSLog(@"blockOper_2_%@_%@",@(i),[NSThread currentThread]);
        }
    }];

    [blockOper_1 addDependency:blockOper_2];
    [queue addOperation:blockOper_1];
    [queue addOperation:blockOper_2];
}

打印结果:

ThreadDemo[5066:1233824] blockOper_2_0_<NSThread: 0x600000078340>{number = 3, name = (null)}
ThreadDemo[5066:1233824] blockOper_2_1_<NSThread: 0x600000078340>{number = 3, name = (null)}
ThreadDemo[5066:1233824] blockOper_2_2_<NSThread: 0x600000078340>{number = 3, name = (null)}
ThreadDemo[5066:1233824] blockOper_2_3_<NSThread: 0x600000078340>{number = 3, name = (null)}
... ...
ThreadDemo[5066:1233824] blockOper_2_999_<NSThread: 0x600000078340>{number = 3, name = (null)}
ThreadDemo[5066:1233822] blockOper_1_0_<NSThread: 0x60000006ae80>{number = 4, name = (null)}
... ...
ThreadDemo[5066:1233822] blockOper_1_997_<NSThread: 0x60000006ae80>{number = 4, name = (null)}
ThreadDemo[5066:1233822] blockOper_1_998_<NSThread: 0x60000006ae80>{number = 4, name = (null)}
ThreadDemo[5066:1233822] blockOper_1_999_<NSThread: 0x60000006ae80>{number = 4, name = (null)}

通过打印结果我们得以看到,添加依赖之后,依赖任务要等待给据任务履行了后才见面开始实施。⚠️,就算依赖任务的预先级重强,也是吃据任务先实行,同时,和先行级不等,依赖关系非让队列的受制,爱啊哪,只要是自己因让您,那尔必须事先实行了,我才行。

队的顶老并发数

身为,这个班最多可出些许任务而实施,或者说最多开发多少条线程,如果安也1,那就是同样糟只能执行一个任务,但是,不要当马上同GCD的串行队列一样,就算最可怜并发数为1,队列任务之尽顺序依然在很多要素。

关于NSOperationQueue再有取消啊,暂停啊等操作方法,大家可以试试一下,应该小心的是,和上GCD的点子不同,不要总是站于面向过程的角度看带这些面向对象的类似,因为她的眉宇对象化的包装过程遭到,肯定有为数不少你看不到的相貌过程的操作,所以你啊从没必要就此用GCD的思辨来效仿用它们,否则你或会见头昏的平等倾糊涂。

线程锁

方到底将多线程操作的方法说话得了了,下面说一下线程锁机制。多线程操作是基本上只线程并行的,所以同样片资源或当同一时间被多个线程访问,举烂的例子就是是进火车票,在纵留一个所时,如果100个线程同时跻身,那么可能达成列车时就有人得干仗了。为了维护世界和平,人民安定,所以我们谈话一下这线程锁。我们事先实现均等段落代码:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.sourceArray_m = [NSMutableArray new];
    [_sourceArray_m addObjectsFromArray:@[@"1",@"2",@"3",@"4",@"5",@"6"]];
    [self threadLock];
}
-(void)threadLock{
    for (int i = 0; i < 8; i++) {
        dispatch_async(self.concurrentQueue, ^{
            NSLog(@"%@",[self sourceOut]) ;
        });
    }
}

-(NSString*)sourceOut{
    NSString *source = @"没有了,取光了";
    if (_sourceArray_m.count > 0) {
        source = [_sourceArray_m lastObject];
        [_sourceArray_m removeLastObject];
    }
    return source;
}

运转打印结果:

ThreadDemo[5540:1291666] 6
ThreadDemo[5540:1291669] 6
ThreadDemo[5540:1291682] 5
ThreadDemo[5540:1291667] 4
ThreadDemo[5540:1291683] 3
ThreadDemo[5540:1291666] 2
ThreadDemo[5540:1291669] 1
ThreadDemo[5540:1291682] 没有了,取光了

咱俩发现6被获下两不成(因为代码简单,执行效率比较快,所以这种情况不实必现,耐心多试几差),这样的话就尴尬了,一布置票卖了2浅,这么歹之行是勿容许容忍的,所以我们得公平之警卫员——线程锁,我们即便开口最直白的点滴种(之前说之GCD的不在少数方式同样可以当于线程锁解决这些题目):

NSLock

代码这样描绘:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.lock = [[NSLock alloc] init];
    self.sourceArray_m = [NSMutableArray new];
    [_sourceArray_m addObjectsFromArray:@[@"1",@"2",@"3",@"4",@"5",@"6"]];
    [self threadLock];
}
-(void)threadLock{
    for (int i = 0; i < 8; i++) {
        dispatch_async(self.concurrentQueue, ^{
            NSLog(@"%@",[self sourceOut]) ;
        });
    }
}
-(NSString*)sourceOut{
    NSString *source = @"没有了,取光了";
    [_lock lock];
    if (_sourceArray_m.count > 0) {
        source = [_sourceArray_m lastObject];
        [_sourceArray_m removeLastObject];
    }
    [_lock unlock];
    return source;
}

运转结果:

ThreadDemo[5593:1298144] 5
ThreadDemo[5593:1298127] 6
ThreadDemo[5593:1298126] 4
ThreadDemo[5593:1298129] 3
ThreadDemo[5593:1298146] 2
ThreadDemo[5593:1298144] 1
ThreadDemo[5593:1298127] 没有了,取光了
ThreadDemo[5593:1298147] 没有了,取光了

如此即便保证了为Lock的资源只能以吃一个线程进行访问,从而为就保证了线程安全。

@synchronized

这个呢酷简短,有时候也会见为此到此,要传一个手拉手对象(一般就是是self),然后用公要加锁之资源放入代码块被,如果该资源有线程正在看时,会叫其他线程等待,直接上代码:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.sourceArray_m = [NSMutableArray new];
    [_sourceArray_m addObjectsFromArray:@[@"1",@"2",@"3",@"4",@"5",@"6"]];
    [self threadLock];
}
-(void)threadLock{
    for (int i = 0; i < 8; i++) {
        dispatch_async(self.concurrentQueue, ^{
            NSLog(@"%@",[self sourceOut]) ;
        });
    }
}

-(NSString*)sourceOut{
    NSString *source = @"没有了,取光了";
    @synchronized (self) {
        if (_sourceArray_m.count > 0) {
            source = [_sourceArray_m lastObject];
            [_sourceArray_m removeLastObject];
        }
    }
    return source;
}

运作结果:

ThreadDemo[5625:1301834] 5
ThreadDemo[5625:1301835] 6
ThreadDemo[5625:1301837] 4
ThreadDemo[5625:1301852] 3
ThreadDemo[5625:1301834] 1
ThreadDemo[5625:1301854] 2
ThreadDemo[5625:1301835] 没有了,取光了
ThreadDemo[5625:1301855] 没有了,取光了

结语

看来该终结了!!!就交即吧,小弟就开足马力了,带大家可个门,这长达路小弟只能陪您活动及及时了。

相关文章