至于iOS多线程,我说,你听,没准你就懂了!艺术

长亭外,古道边,芳草碧连天。

晚风拂柳笛声残,夕阳山外山?

天之涯,地之角,知交半凋谢?

人生难得是聚会,只有别离多?

长亭外,古道边,芳草碧连天。

问君此去啥时候还,来时莫迟疑?

天之涯,地之角,知交半衰落?

一壶浊洒尽余欢,今宵别梦寒。

事出必有因,今天自己想和你聊聊线程的由来就是——当然是针对一个共产党人的思想觉悟,为苍生透析生命,讲解你正在蒙圈的知识点,或者想破脑袋才意识这么简单的技艺方案。

过几人学线程,迷迷糊糊;很三个人问线程,有所期待;也有成百上千人写线程,分享认知给正在全力的后生,呦,呦,呦呦。可是,你真的精通线程么?你真的会用多线程么?你实在学了然,问清楚,写清楚了么?不管您明不明白,反正自己不知道,不过,没准,你看完,你就知道了。



前言

  • 事关线程,这就只可以提CPU,现代的CPU有一个很重点的特征,就是岁月片,每一个取得CPU的任务只好运行一个刻钟片规定的流年。
  • 实质上线程对操作系统来说就是一段代码以及运行时数据。操作系统会为各样线程保存相关的数量,当接收到来自CPU的时间片中断事件时,就会按自然规则从那么些线程中甄选一个,复苏它的运行时数据,这样CPU就足以继续执行这些线程了。
  • 也就是实际上就单核CUP而言,并从未艺术落实真正含义上的现身执行,只是CPU急忙地在多条线程之间调度,CPU调度线程的时刻丰裕快,就造成了多线程并发执行的假象。并且就单核CPU而言多线程可以解决线程阻塞的题材,不过其自我运行效能并不曾提高,多CPU的互相运算才真的化解了运行效能问题。
  • 系统中正在运行的每一个应用程序都是一个经过,每个过程系统都会分配给它独立的内存运行。也就是说,在iOS系统中中,每一个使用都是一个过程。
  • 一个历程的具有任务都在线程中开展,因而各种过程至少要有一个线程,也就是主线程。这多线程其实就是一个经过开启多条线程,让具备任务并发执行。
  • 多线程在早晚意义上贯彻了经过内的资源共享,以及效用的升官。同时,在必然水平上相对独立,它是先后执行流的蝇头单元,是经过中的一个实体,是履行顺序最基本的单元,有投机栈和寄存器。
  • 地点这些你是不是都领悟,不过自己偏要说,哦呵呵。既然我们聊线程,这咱们就先从线程开刀。

说起《送别》这首词,几乎已经是众所周知,妇孺皆知了。

Pthreads && NSThread

先来看与线程有最直白关联的一套C的API:

二〇一七年1十月13日夜间,朴树出现腾讯视频《大事发声》直播现场。

Pthreads

POSIX线程(POSIX
threads),简称Pthreads,是线程的POSIX标准。该专业定义了创立和操纵线程的一整套API。在类Unix操作系统(Unix、Linux、Mac
OS X等)中,都采纳Pthreads作为操作系统的线程。

当晚,朴树演唱了新专辑《猎户星座》的多首歌曲。另外还有《平凡之路》、《生如夏花》、《送别》等多首经典歌曲。

震古烁今上有木有,跨平台有木有,你没用过有木有!下边大家来看一下以此近乎牛逼但的确基本用不到的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

当唱到最终一曲《送别》时,他忽然崩溃大哭,扶着麦克(Mike)风把头深深埋下,心绪激动到不能持续唱下去,足以注解这首歌的感染力。

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];了。(不要慌,往下看…
…)



GCD

GCD,全名Grand Central Dispatch,中文名郭草地,是遵照C语言的一套多线程开发API,一听名字就是个狠角色,也是眼下苹果官方推荐的多线程开发情势。能够说是使用方便,又不失逼格。总体来说,他解决自身提到的下边直接操作线程带来的难题,它自动帮你管理了线程的生命周期以及任务的举行规则。下边我们会频繁的商议一个词,这就是任务,说白了,任务骨子里就是你要执行的那段代码

正文就带您认识一下这位举世无双的师父:李叔同

任务管理艺术——队列

下边说当大家要管住四个任务时,线程开发给我们带来了迟早的技术难度,或者说不方便性,GCD给出了我们归总管理职责的主意,这就是队列。我们来看一下iOS多线程操作中的队列:(⚠️不管是串行仍然并行,队列都是比照FIFO的标准化依次触发任务)

影视《一轮明月》

四个通用队列:
  • 串行队列:所有任务会在一条线程中执行(有可能是眼下线程也有可能是新开辟的线程),并且一个职责执行完毕后,才起来实施下一个职责。(等待完成)
  • 互相队列:可以敞开多条线程并行执行任务(但不自然会敞开新的线程),并且当一个任务放到指定线程发轫施行时,下一个职责就可以开端实施了。(等待暴发)

李叔同,祖籍湖北,学贯中西,艺专多科。他在成千上万的措施世界都有开创性的孝敬,是资深书道家、美术翻译家、音乐家、戏剧活动家,是中华音乐剧的祖师爷之一。

三个非常队列:
  • 主队列:系统为我们创制好的一个串行队列,牛逼之处在于它管理必须在主线程中实施的任务,属于有劳保的。
  • 大局队列:系统为大家创造好的一个相互队列,使用起来与我们团结创制的互动队列无真相差别。

1918年19月19日,他在大阪虎跑寺出家,法名演音,号弘一,世称弘一法师。

任务执行措施

说完队列,相应的,任务除了管理,还得执行,要不然有钱不花,掉了纸上谈兵,并且在GCD中并无法直接开辟线程执行任务,所以在任务出席队列之后,GCD给出了二种实施措施——同步施行(sync)和异步执行(async)。

  • 协办实施:在当前线程执行任务,不会开发新的线程。必须等到Block函数执行完毕后,dispatch函数才会重临。
  • 异步执行:可以在新的线程中举行任务,但不肯定会开发新的线程。dispatch函数会立刻赶回,
    然后Block在后台异步执行。

她是中华近代佛教史上一位突出的道人,南山律宗的第十一代祖师。

地点的这个理论都是自个儿在许多被套路背后总括出来的血淋淋的经验,与君共享,可是如此写自己猜你肯定依然不晓得,往下看,说不定有悲喜吧。

任务队列组合措施

深信这个题目你看过许多次?是不是看完也不理解到底怎么用?这么巧,我也是,请相信下边那一个自然有你不精通并且想要的,我们从多少个最直白的点切入:

公认的多面手和奇才:

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执行完毕后,这个异步执行的内部函数会顺序执行)。

作为中国新文化运动的先辈,他最早将西方水墨画、钢琴、话剧等引入国内,且以擅书法、工诗词、通丹青、达音律、精金石、善演艺而驰名于世。

咱俩说说队列与履行形式的陪衬

上边说了系统自带的五个体系,下边我们来用自己制造的系列讨论一下各样搭配情形。
俺们先创建多少个系列,并且测试方法都是在主线程中调用:

//串行队列
self.serialQueue = dispatch_queue_create("serialQueue.ys.com", DISPATCH_QUEUE_SERIAL);
//并行队列
self.concurrentQueue = dispatch_queue_create("concurrentQueue.ys.com", DISPATCH_QUEUE_CONCURRENT);

她在近代文艺领域里无不涉足,诗词歌赋音律、金石篆刻书艺、丹青工学戏剧皆早具才名。

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}

全方位都在近日线程顺序执行,也就是说,同步施行不具有开发新线程的能力。


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。表达异步执行具有开发新线程的能力,并且串行队列必须等到前一个任务执行完才能起头履行下一个职责,同时,异步执行会使其中函数率先再次回到,不会与正在履行的外部函数暴发死锁。

音乐艺术:

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函数才会回去,才能继续向下执行,所以我们看看的结果是逐一打印的。

李叔同是神州现代歌史的启蒙先驱。

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对于不同线程的调度分配,可是,线程不是无偿无限开拓的,当任务量丰盛大时,线程是会再度利用的。

接受了北美洲音乐文化的李叔同,把部分亚洲歌曲的现成曲调拿来,由他自己填写了新词。

划一下重中之重啊

李叔同不仅是炎黄“学堂乐歌”最为金榜题名的作者,而且较早注意将中华民族传统文化遗产作为高校乐歌的题材。

1. 对此单核CPU来说,不设有真正意义上的相互,所以,多线程执行任务,其实也只是一个人在做事,CPU的调度控制了非等待任务的执行速率,同时对于非等待任务,多线程并不曾真的意义升高功能。

她于1905年编印出版的供高校教学用的《国学唱歌集》。

2. 线程能够简简单单的以为就是一段代码+运行时数据。

《国学唱歌集》是从《诗经》、《天问》和古诗词中选出13篇,配以西洋和日本曲调,连同两首海门山歌剧的译谱合集而成的。

3. 同步实施会在现阶段线程执行任务,不拥有开发线程的能力或者说没有必要开辟新的线程。并且,同步施行必须等到Block函数执行完毕,dispatch函数才会回去,从而阻塞同一串行队列中外部方法的施行。

个中的《祖国歌》,依然当下为数较少、以中国民间曲调来填词的一首学堂乐歌,激发了学员的爱国热情。

4. 异步执行dispatch函数会直接重临,Block函数我们得以认为它会在下一帧参加队列,并基于所在队列近来的职责情形极其下一帧执行,从而不会卡住当前外部任务的举行。同时,唯有异步执行才有开拓新线程的画龙点睛,可是异步执行不必然会开发新线程。

后来,他东渡日本,学习了天堂音乐、美术、戏剧理论,主攻钢琴。

5. 如假诺队列,肯定是FIFO(先进先出),但是什么人先实施完要看第1条。

她是国内率先个用五线谱作曲的人,他还创建了华夏率先部音乐刊物《音乐小杂志》。

6. 假使是串行队列,肯定要等上一个职责履行到位,才能初步下一个任务。但是互相队列当上一个职责先河实施后,下一个任务就足以起来实践。

她大力提倡音乐“商量道德,促社会之系数,练习性情,感精神之粹美”的社会教化成效。

7. 想要开辟新线程必须让任务在异步执行,想要开辟三个线程,只有让任务在互相队列中异步执行才足以。执行办法和队列类型多层组合在自然水准上可以实现对于代码执行顺序的调度。

还要发布了《我的国》、《隋堤柳》等怀国忧民的乐歌。李叔同一生迄今留存的乐歌作品70余首。

8. 联袂+串行:未开发新线程,串行执行任务;同步+并行:未开发新线程,串行执行任务;异步+串行:新开发一条线程,串行执行任务;异步+并行:开辟多条新线程,并行执行任务;在主线程中一道运用主队列执行任务,会造成死锁。

编作的乐歌继承了中国古典诗词的优秀传统,大多为借景抒情之作,填配的文辞依永秀丽,声辙抑扬顿挫有致,意境深刻而丰裕韵味。

8. 对于多核CPU来说,线程数量也不可以最好开拓,线程的开拓同样会消耗资源,过多线程同时处理任务并不是您想像中的人多力量大。

添加他所有相比全面的中西音乐文化修养,选拔的多为欧美各国的伊始名曲,曲调精粹动人,清新流畅,词曲的结缘贴切顺达,相得益彰,达到了很高的艺术水平。

GCD其他函数用法

于是,他的乐歌作品广为青年学生和文人热爱,像《送别》、《忆儿时》、《梦》、《大明湖》等,特别是《送别》,先后被电影《早春1月》、《城南往事》成功地选作插曲或核心歌。

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)}

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}
无论你怎么疯狂的点击,在第一次打印之后,输出台便岿然不动。

戏曲艺术:

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;
}

李叔同是礼仪之邦舞剧运动的前人、中国音乐剧的成立人。他是华夏先是个相声剧团体“春柳社”的首要成员。

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

老铁,发现了吗?这六个函数对于队列的栅栏成效是千篇一律的,然而对于该函数相对于另外中间函数遵守了最伊始说到的一路和异步的规则。你是不是有点懵逼,如若您蒙蔽了,那么请在每一个出口后边打印出脚下的线程,假若您要么懵逼,那么请您再次看,有劳,不谢!

1907年(清光绪三十三年)中秋表演的这扯《茶花女》,是国人上演的首先部舞剧,李叔同在剧中饰演女主角玛格Rita。

5. dispatch_apply

该函数用于重复执行某个任务,假使任务队列是互为队列,重复执行的天职会并发执行,即使任务队列为串行队列,则任务会挨个执行,需要小心的是,该函数为同步函数,要制止线程阻塞和死锁哦,老铁。

新兴,他还曾主演独幕剧《生相怜》、《美学家与其妹》和改编自随笔《汤姆(Tom)小叔的斗室》的舞剧《黑奴吁天录》。

串行队列:
-(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)}

李叔同的戏剧活动虽如星光一闪,却照亮了中华诗剧发展的征程,开启了炎黄话剧的蒙古包。

死锁:
-(void)GCDApply{
    //重复执行
    dispatch_apply(5, dispatch_get_main_queue(), ^(size_t i) {
        NSLog(@"第%@次_%@",@(i),[NSThread currentThread]);
    });
}

运行结果:

特别是在相声剧的布景设计、化妆、服装、道具、灯光等重重主意方面,更是起到了开风气之先的启蒙功能。

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时,所有任务等待,信号量越大,允许可并行执行的职责数量越多。

在音乐下面,李叔同是作词、作曲的豪门,也是国内最早从事乐歌创作取得丰富成果并有深刻影响的人。

GCD就先说到这,很多API没有涉嫌到,有趣味的同班们可以协调去探望,重要的是办法和习惯,而不是您看过多少。


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自我是个抽象类,不能够直接动用,我们有二种方法给予它新的生命,就是下面这五个东西,您坐稳看好。

他是礼仪之邦现代水墨画艺术的最早创作者和倡导者。

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] 没有了,取光了

旅居迪拜时,他将过去所作诗词手录为《诗钟汇编初集》,在“城南文社”社友中传阅,后又聚集《李庐诗钟》。

结语

因而看来该寿终正寝了!!!就到这吗,三弟已经努力了,带我们入个门,这条路大哥只好陪你走到这了。

剃度前夕,他将清光绪二十六至三十三年,也就是1900—1907年间的20多首诗词自成书卷。

个中就有《留别祖国并呈同学诸子》、《哀国民之心死》等重重值得称颂的墨宝,表现了笔者对国家命局和民生疾苦的浓密关怀。

剃度前的五六年间,他还有30余首歌词问世。

这些作品,通过艺术的伎俩表明了众人在相同碰着中大多会暴发的思维激情,曾经流行一时,有的改为遥远的传世之作。

弘一法师对联语也有长远兴趣,并有极高的玩味和撰写水平。

尤其是出家后,大师为四处佛寺和缁素撰写的成千上万嵌字联语,更表现出她的奇思妙想和深厚的方法底蕴。

他书写的这么些情节深远、极富哲理的名联,现也变为警示后人的一笔宝贵的学问艺术财富。


书法篆刻:

李叔同在书法艺术上的形成为世人所瞩目。

他的书法早期脱胎魏碑,笔势开张,逸宕灵动。先前时期则自成一体,冲淡朴野,温婉清拔。

专程是出家后的作品,更充满了骄人的安静和云鹤般的淡远。

这是万紫千红分外的枯燥、雄健过后的文武、老成之后的稚朴,恰如他本人表白的这样:“朽人之字所示者,平淡、恬静、冲逸之致也。”

李叔同的篆刻可谓独树一帜。

她过去治印从秦汉出手,兼攻浙派。

35岁这年入“西泠印社”。

39岁在维尔纽斯虎跑定慧寺出家前,将根本篆刻作品和藏印赠与“西泠印社”。

该社为之筑“印冢”并立碑以记其事。

治印赏印论印,是她终其一生未曾丢弃的嗜好。

她在给友人的信中提道:“刀尾扁尖而平齐若锥状者,为朽人自意所创。

锥形之刀,仅能刻白文,如以铁笔写字也。扁尖形之刀可刻朱文,终不免雕琢之痕,不若以锥形刀刻白文能自然之情趣也。”

李叔同对印学的进献还显示在她对近代篆刻事业的发扬上。

他亲身倡导建立了继“西泠印社”之后的又一印学团体——乐石社,定期雅集,并编印印社著作集和史料汇编。这也是在近代篆刻史上领风气之先之事。

弘一和她的书法亦谓国之至宝,华夏之光。

她的书法犹如浑金璞玉,清凉超尘,精严净妙,闲雅冲逸、富有乐感,朴拙中见品格,以无态备万态。

她将法家的谦逊、法家的当然、释家的静寂蕴涵在书艺之中。

弘一法师临近中年摒弃诸艺和身外之物遁入空门后,惟书法不辍,书写佛语,广结善缘,普度众生,秉持文艺应“以人传文艺,不以文艺传人。”

弘一法师既是才气横溢的法门哲学家,也是一代高僧,“二十篇章惊海内”的大师傅。

他将中国太古的书法艺术推向了极至,“朴拙圆满,浑若天成”,鲁迅、郭沫若等现代文化名家以博取师父一幅字为无上赏心悦目。


迷信佛教:

1918年2月19日,他在阿塞拜疆巴库虎跑寺出家,法名演音,号弘一,皈依佛教之后,一洗铅华,笃志苦行,成为世人敬仰的一代佛教宗师。

为振兴律学,不畏困苦,深远研修,潜心戒律,著书说法,实践躬行。

他是近年佛教界倍受爱慕的律宗大师,也是国内外佛教界著名的僧侣。

弘一大师入佛初期,除了读书僧人必读的经典,其进修博览而广纳。

再者说,他原是个对任何事情,除非不做,做就要做得认真彻底的人。做了和尚,在佛学思想方面,自然也得做出自己的特性。

对此,林子青概括说:“弘一大师的佛学思想连串,是以华严为镜,四分律为行,导归净土为果的。也就是说,他探讨的是华严,修持弘扬的是律行,崇信的是天堂法门。

她对晋唐诸译的华严经都有精深的研讨,曾著有《华严集联三百》。

中原禅宗律学,故译有四大律,即《十诵律》、《四分律》、《摹诃借祗律》、《五分律》。

为弘扬律学,弘一大师穷研《四分律》,花了4年时光,著成《四分律比丘戎相表记》。

此书和她余生所撰的《南山律在家备览略篇》,弘扬佛法,合为精心创作的两大名著。

他被佛教弟子奉为律宗第十一代世祖。

师父圆寂近70周年,嘉言懿行早已载入中华史册, 成为后人敬仰的一代高僧。

她传奇的终身为我国近代文化、艺术、教育、宗教领域里都做出了重点的贡献,堪称一流的文艺先驱,他爱国的雄心和义举更连贯了弘一大师的百年。


怜虫摇椅

弘一法师一生严守律宗戒律,悲天悯人,他去学生丰子恺家,每一次坐木藤椅时总要摇摇木藤椅才下座。

丰子恺刚先导不佳问,但见他频繁这样,就出言问他何以如此。

弘一法师答道,这些木藤椅可能会有小虫,这样摇摇后这多少个小生命就跑开了,坐下来后不一定杀生。

活佛临终时曾要求弟子在龛脚垫上四碗水,以免蚂蚁爬上尸身被不小心烧死,其爱心可见一斑。


咸有咸的滋味,淡也有淡的寓意

有一天,他的故交夏丐尊来拜访她,吃饭时,他只配一道咸菜。

夏丐尊不忍的问他:“难道这咸菜不会太咸吗?”

“咸有咸的味道。”弘一大师回答道。

吃完饭后,弘一大师倒了一杯白开水喝,夏丐尊又问:“没有茶叶吗?怎么喝这干燥的沸水?”

弘一大师笑着说:“开水虽淡,淡也有淡的味道。”


弘一大师未出家前就已经名满天下,出家后更加受人刮目相看,但他却这般严苛遵照正命,拒绝过度丰满的赡养,将全身心都沉浸在佛法中。

弘一大师李叔同为世人留下了音乐,随想,书法,戏剧,佛学等多地点的至宝,永远值得我们上学。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图