通俗易懂多线程

一. 进程

1. 正在运行的应用程序
2. 迅雷进程和xcode进程相互独立
3. 一个应用程序可以对应多个进程

二. 线程(真正执行任务的单位)

1. 每1个进程至少要有一个线程

三. 串行(执行任务的方式)

1. 一个线程中任务的执行是串行的(串行:依次执行)
2. 在同一个时间内,1个线程只能执行一个任务

四. 并行和并发

1. 多个线程一起执行任务,指的是同一时间处理多个任务的能力
2. 并发:CUP在线程之间来回切换

五. 进程和线程的比较

1. 线程是CUP调用(执行任务)的最小单位.
2. 进程是CUP分配资源和调度的单位.
3. 一个程序可以对应多个进程,一个进程中可以有多个线程,但至少要有一个线程.
4. 同一个进程内的线程共享进程的资源.

理解方法进程和线程之间的关系: 进程好比工厂;线程好比工人
描述
注意: CUP在调动的时候是以线程为单位的

六. 多线程

1. 同时开启多条线程进行任务
注意: 开发当中开3到5条线程就可以,最多不能超过6条线程
2. 如果开启大量的线程,会降低程序的性能

七. 耗时操作

注意: 将耗时操作放到主线程会让APP卡顿
//耗时操作,用一个for循环既能检测出当前线程是主线程还是子线程,还能检测出耗时操作在主线程中的影响
    for (NSInteger i = 0; i < 100000; i++) {
        NSLog(@"%zd-----%@",i,[NSThread currentThread]);
    }
1. 将耗时操作放到子线程处理会使APP执行更流畅
2. 注意: 所有的UI操作必须放到主线程中去执行

八. 注意

1. 系统的大部分的方法默认都是在主线程中执行的
2. 获得当前线程
//获取当前的线程
    NSThread *currentThread = [NSThread currentThread];
3. 如何判断主线程
3.1 打印线程 看–>number == 1 主线程 number != 1 子线程

判断是子线程还是主线程

3.2 类方法
//判断主线程
    BOOL isMain = [NSThread isMainThread];
4. 用for循环模拟耗时操作
 //获取主线程
    NSThread *mainThread = [NSThread mainThread];

    //获取当前的线程
    NSThread *currentThread = [NSThread currentThread];

    //打印出参数可以看出主线程和当前线程
    NSLog(@"%@---%@",mainThread,currentThread);

    //判断主线程
    BOOL isMain = [NSThread isMainThread];

    NSLog(@"%d",isMain);

    //判断当前线程的类型是否为主线程
    BOOL isMain2 = [currentThread isMainThread];

    NSLog(@"%d",isMain2);

    //耗时操作,用一个for循环既能检测出当前线程是主线程还是子线程,还能检测出耗时操作在主线程中的影响
    for (NSInteger i = 0; i < 100000; i++) {
        NSLog(@"%zd-----%@",i,[NSThread currentThread]);
    }

九. 多线程实现方案

1. GCD(重点掌握):
2. NSOperation(重点掌握):封装了很多GCD不具备的方法,本身是继承GCD的,所以拥有GCD的方法
3. NSThread(掌握):
3.1 子线程创建方式一–>[NSThread alloc] initWithTarget:
3.1.1 创建完线程需要手动执行
 //创建线程
    /*
     第一个参数:目标对象 self
     第二个参数:方法选择器 调用方法的名称
     第三个参数:调用方法的参数 没有着传值nil
     */
    XFThreadA *threadA = [[XFThreadA alloc] initWithTarget:self selector:@selector(run:) object:@"创建线程A"];

    //设置线程名字
    threadA.name = @"线程A";

    //手动开启--->开始线程
    [threadA start];
3.2 子线程创建方式二—>[NSThread detachNew…];不需要手动开启,系统会主动开启
//创建线程,不需要手动开启
    [XFThreadA detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"创建了线程D"];
3.3 子线程创建方式三—>[self per….];创建一个后台线程
 [self performSelectorInBackground:@selector(run:) withObject:@"创建了后台线程B"];
3.4 子线程创建方式四—>[[NSThread alloc] init];需要自定义一个类,继承线程,然后重写main方法,将需要执行的线程方法放在main方法中
3.5 设置线程名称(name);线程的优先级(threadPriority)
3.6 优先级高的线程不一定是先执行完毕;
3.7 优先级高的意思是:CUP调度次数比较高,执行的次数比较高
4. 当线程中所以的任务都执行完毕的时候,线程才会被释放
​思路:自定义一个类,继承NSThread,在自定义的类中重写delloc方法,然后用自定义的类创建线程,最后由打印的结果不难看出,只有当线程中所有的任务都执行完了,才会被销毁.
5. pthread(了解):创建子线程
    //创建一个线程对象
    pthread_t thread;
    /*
     第一个参数:线程对象 传递的是地址
     第二个参数:线程的属性 NULL
     第三个参数:要调用的函数(指向函数的指针)
     第四个参数:函数需要接受的参数 NULL
     */
     //执行线程中的任务run
    pthread_create(&thread, NULL, run, NULL);

    //创建一个线程对象
    pthread_t thread1;

    //执行线程中的任务run
    pthread_create(&thread1, NULL, run, NULL);
}

void *run(void *param)
{
    //打印当前线程
    NSLog(@"%@",[NSThread currentThread]);

    //执行耗时操作
    for (NSInteger i = 0; i < 1000000; i++) {
        NSLog(@"%zd-----%@",i,[NSThread currentThread]);
    }

    return NULL;

}

十. 一旦线程死亡了,就不能再调用了

1. 未来在执行;过去执行
 //在未来执行
    [NSThread sleepUntilDate:[NSDate distantFuture]];
2. 当线程执行到某个时间段,退出线程exit(强制退出);return(自然死亡);break(自然死亡)
for (NSInteger i = 0; i < 100000; i++) {
        NSLog(@"%zd-----%@",i,[NSThread currentThread]);

        //执行到某个段,跳出线程
        if (i == 50) {
            //这是强制退出
            [NSThread exit];
        }
    }

十一. 多线程的安全

1. 实例:存钱;卖票;苹果官方实例
售票员卖票的例子: 存在安全隐患
举例: 假如有两个售票员A和B,车票有1000张,A和B是独立的,当A卖出一张票的时候,此时B也正巧在同样的时间段卖出一张票,意思是都在执行同一个操作,剩下的车票数量为999张,这是不合理的,这就存在安全问题.
解决问题: 当售票员A在卖出一张票的时候,让售票员B对剩下的车票没有使用权,只有当剩下的车票更新为999张的时候,才能让售票员B对其进行操作,这样就能解决安全问题了.
实际对代码的操作: 加互斥锁
2. 代码演示线程安全问题
方法: 加互斥锁
    @synchronized(self) {....代码块....};
2.1 锁对象必须是同一个,加多把锁是无效的
2.2 锁对象只要是唯一的就可以,以后开发直接传self
2.3 加锁需要注意放置锁的位置
2.4 不要乱加锁,加锁的前提条件:多个线程访问同一个资源
2.5 加锁是需要耗费性能的
加锁能达到效果的原理: 当第一个售票员卖票的时候,他讲所有的票都上锁,那么后面的售票员就只能排队等着,等第一个售票员卖完一张后,他就把锁打开,排在后面的售票员发现票没上锁,就开始出售,出售的时候他也将所有的票上锁,那么后面的售货员发现上锁了,就等在外面,等钱一个售票员卖完,解锁,就这样一个循环,将所有的票都卖完.
3. 线程同步(按照固定的顺序实现的)
4. 线程异步

十二. 原子核非原子属性选择

1. atomic:线程安全,需要消耗大量的资源
2. nonatomic:非线程安全,适合内存小的移动设备.

十三. 下载图片

1. 如何计算代码执行花费的时间2中方法

第一种:

 //开始时间
    NSDate *date = [NSDate date];

    //获取路径
    NSURL *url = [NSURL URLWithString:@"http://cdn.duitang.com/uploads/item/201503/15/20150315204312_4kJAT.jpeg"];

    //下载图片的二进制数据到本地
    NSData *data = [NSData dataWithContentsOfURL:url];

    //转化格式
    UIImage *image = [UIImage imageWithData:data];

    //结束时间
    NSDate *end = [NSDate date];

    //打印出时间
    NSLog(@"%f",[end timeIntervalSinceDate:date]);

    self.imageView.image = image;
}

第二种:

//确定路径
    NSURL *url = [NSURL URLWithString:@"http://h.hiphotos.baidu.com/image/pic/item/d439b6003af33a8716116e60c55c10385343b548.jpg"];

    //获取时间
    CFTimeInterval start = CFAbsoluteTimeGetCurrent();

    //下载图片到本地
    NSData *data = [NSData dataWithContentsOfURL:url];

    //获取代码执行结束时间
    CFTimeInterval end = CFAbsoluteTimeGetCurrent();

    //打印出时间差
    NSLog(@"%f",end - start);

    //装换图片格式
    UIImage *image = [UIImage imageWithData:data];

    //赋值
    self.imageView.image = image;
    NSLog(@"%@-------",[NSThread currentThread]);
2. 下载图片是在子线程进行的,显示图片是在主线程进行的
3. 回到主线程
3.1 从一个线程跳到另外一个线程,只能用下面方法
 //回到主线路,刷新UI
    [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
4. 掌握—>setImage:中的image本身就是一个属性

十四. GCD–>牛逼的中枢调度器

1. 什么是队列?
解答: 队列是有两个口,先进先出,后进后出

这里写图片描述

2. 执行任务(同步和异步)
​2.1 同步:只能在当前线程中执行任务,不具备开启新线程的能力
2.2 异步:可以在新的线程中执行任务,具备开启新线程的能力
3. 容易混淆的术语(特指的是GCD里面的术语)
3.1 函数,都是用来执行任务的
同步函数: 没有开线程的能力,只能在当前线程中执行
特点: 必须要得到该方法的返回值,才能够继续往下执行—>如果我没有执行完毕,那么后面的任务将永远无法执行
异步函数: 具备开线程的能力,可以开线程
特点: 可以继续往下执行,等前面的任务执行完毕之后再回头执行–>无所谓,可以先执行后面的任务
3.2 队列,都是用来存放任务–block
并发队列: 允许多个任务同时执行
队列,都是用来存放任务
并发队列:允许多个任务同时执行
    1)直接create dispatch_queue_create
    2)全局并发队列
串行队列: 只能一个接着一个执行
串行队列:只能一个接着一个的执行
    1)直接create dispatch_queue_create
    2)主队列:
        1)所有在主队列中的任务都会被放在主线程中执行
        2)主队列中的任务在执行之前会先检查主线程的状态,
          如果发现主线程当前正在执行任务那么会暂停队列中任务的调度
3.3 并不是有几个任务,就会开几条线程
3.3.1
//异步函数+并发队列
//会不会开线程:会
//如果开线程,那么开几条?多条(并不是有几个任务就开几条线程)
//队列内部任务如何执行:并发
3.3.2
//异步函数+串行队列
//会不会开线程:会
//如果开线程,那么开几条?1
//队列内部任务如何执行:串行
3.3.3
//同步函数+并发队列
//会不会开线程:不会
//如果开线程,那么开几条 X
//队列内部任务如何执行:串行
3.3.4
//同步函数+串行
//会不会开线程:不会
//如果开线程,那么开几条 X
//队列内部任务如何执行:串行
注意: 同步函数,主队列:锁死
#pragma mark - 同步函数,主队列
//不会开线程
//出现锁死情况:因为当执行到封装任务的时候,将任务加到主队列执行,由于是同步函数,不会开线程,只能等上一个任务执行完了,才会往下执行,但是加在主队列的任务还在执行,那么就出现了等待的情况,所以就会出先锁死情况
注意: 1> 异步函数,主队列:不会开新的线程,所有任务串行
2> 如果发现你等我,我等你的情况,那么就死锁了.

十五. GCD线间通信(掌握)

1. 加载UI一定要在主线程中进行,下面一段GCD线程间的通信,通过打印,可以看出来UI是在主线程中进行的
//点击调用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    //开线程下载图片
    dispatch_async(dispatch_get_global_queue(0, 0), ^{

        //判断是主线程还是子线程
        NSLog(@"%@",[NSThread currentThread]);

        //获取路径
        NSURL *url = [NSURL URLWithString:@"http://www.yybagua.cn/uploads/allimg/141213/4-1412131ZQC25.jpg"];

        //下载图片到本地
        NSData *data = [NSData dataWithContentsOfURL:url];

        //转换图片
        UIImage *image = [UIImage imageWithData:data];

        //刷新UI
        dispatch_sync(dispatch_get_main_queue(), ^{
            self.imageView.image = image;
            //判断是主线程还是子线程(通过打印出来的结果,UI是在主线程中执行的)
            NSLog(@"%@",[NSThread currentThread]);
        });
    });
}

十六. 总结出来有关多线程的笔记,希望能作为大家的参考,如果有不足的地方,麻烦大家给我留言,谢谢!!!!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java面经是指在面试过程中常被问到的与Java相关的问题和知识点。下面是一些常见的Java面经问题及其解答: 1. Java的特点是什么? Java是一种面向对象的编程语言,具有跨平台性、简单性、可靠性、安全性和高性能等特点。 2. 什么是Java虚拟机(JVM)? JVM是Java程序运行的环境,它负责将Java源代码编译成字节码,并在不同的操作系统上执行。 3. 什么是面向对象编程(OOP)? 面向对象编程是一种编程范式,它将数据和操作数据的方法封装在一起,通过创建对象来实现程序的功能。 4. Java中的四种访问修饰符分别是什么? Java中的四种访问修饰符分别是public、protected、default和private,用于控制类、方法和变量的访问权限。 5. 什么是Java中的异常处理机制? 异常处理机制是Java中用于处理程序运行过程中出现的异常情况的一种机制,通过try-catch-finally语句块来捕获和处理异常。 6. 什么是Java中的多线程多线程是指在一个程序中同时执行多个线程,每个线程都可以独立执行不同的任务,提高程序的并发性和效率。 7. 什么是Java中的集合框架? 集合框架是Java中用于存储和操作一组对象的类库,包括List、Set、Map等常用的数据结构和算法。 8. 什么是Java中的反射机制? 反射机制是指在运行时动态地获取和操作类的信息,可以通过反射来创建对象、调用方法和访问属性等。 9. 什么是Java中的IO流? IO流是Java中用于输入和输出数据的一种机制,包括字节流和字符流,用于读取和写入文件、网络等数据源。 10. 什么是Java中的设计模式? 设计模式是一种解决常见软件设计问题的经验总结,包括单例模式、工厂模式、观察者模式等常用的设计模式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值