iOS多线程之一:进程,线程,队列的关系

1,328 阅读6分钟

「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战

进程与线程

什么是进程

进程是系统中正在运行的一个程序,程序一旦运行就是进程

什么是线程

线程进程中执行运算的最小单位,负责当前进程中程序的执行。

进程与线程的关系。

一个进程至少有一个线程,一个进程可以运行多个线程,同一进程的多个线程可共享数据。

进程与线程的区别

进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。

线程与队列

线程与队列的关系

队列是用于保存以及管理任务的,线程负责去队列中取任务进行执行。也可以理解为队列调度任务给到线程中执行。

主线程

iOS中为什么刷新UI是在主线程中呢?

因为UIKit框架不是线程安全的,当多个线程同时操作UI的时候,可能会出现抢夺资源、读写问题,导致崩溃,UI异常等问题。

队列

队列是一种先进先出的数据结构,是一个特殊的线性表,也就是我们说的FIFO,我们也可以理解为排队。

串行队列:只开启一个线程,每次只能有一个任务执行,等待执行完毕后才会执行下一个任务。其中主队列也是一种特殊的串行队列主队列的任务是在主线程中执行。

并发队列:可以让对个任务同时执行,也就是开启多个线程,让多个任务同时执行。我们简单理解就是并发队列有任务AB,任务A交给线程A执行,如果是异步调度,这时候不用等任务A完成,任务B就可以交给线程B执行。其中全局队列也是一种并发队列

任务

任务就是执行代码的操作。任务的执行方式有同步执行异步执行

同步执行:在当前线程中执行任务,任务没有执行完毕之前是不会执行下一个任务,而且只能在一个线程中执行,所以我们说同步操作会堵塞线程。不具备开启线程能力。

异步执行:在新的线程中执行任务,添加任务的时候会立即返回,不会堵塞线程,具备开启线程能力。

同步串行

dispatch_queue_t queue = dispatch_queue_create( "jj.com" , DISPATCH_QUEUE_SERIAL);

    for ( int  i = 0; i < 5; i++) {

        dispatch_sync(queue, ^{
            
            if (i == 2) {
                sleep(2);
            }
            
            NSLog (@ "%@ %d" , [ NSThread  currentThread], i);
        });
    }
    NSLog (@"同步串行完成");

我们看下同步串行输出结果:

2022-02-13 22:45:58.590740+0800 多线程[61384:1124644] <_NSMainThread: 0x600001f9c300>{number = 1, name = main} 0

2022-02-13 22:45:58.591959+0800 多线程[61384:1124644] <_NSMainThread: 0x600001f9c300>{number = 1, name = main} 1

2022-02-13 22:46:00.593617+0800 多线程[61384:1124644] <_NSMainThread: 0x600001f9c300>{number = 1, name = main} 2

2022-02-13 22:46:00.594050+0800 多线程[61384:1124644] <_NSMainThread: 0x600001f9c300>{number = 1, name = main} 3

2022-02-13 22:46:00.594434+0800 多线程[61384:1124644] <_NSMainThread: 0x600001f9c300>{number = 1, name = main} 4

2022-02-13 22:46:00.594847+0800 多线程[62708:1130460] 同步串行完成

同步串行:可以看到打印顺序是是按正常顺序执行,当前方法是在主线程中执行,可以看到name=main也是在主线程中执行,也就是说不具备开启线程能力,并且执行任务是一个执行完后,再执行另外一个任务。最后打印同步串行完成也是能表面同步堵塞了主线程

同步并发

dispatch_queue_t queue = dispatch_queue_create( "jj.com" , DISPATCH_QUEUE_CONCURRENT);

    for ( int  i = 0; i< 5; i++) {
        dispatch_sync(queue, ^{
            if (i == 2) {
                sleep(2);
            }
            NSLog (@ "%@ %d" , [ NSThread  currentThread], i);
        });
    }
    NSLog (@"同步并发完成");

我们看下同步并发输出结果:

2022-02-13 23:00:07.548954+0800 多线程[65378:1141271] <_NSMainThread: 0x600003fb0280>{number = 1, name = main} 0

2022-02-13 23:00:07.549225+0800 多线程[65378:1141271] <_NSMainThread: 0x600003fb0280>{number = 1, name = main} 1

2022-02-13 23:00:09.550559+0800 多线程[65378:1141271] <_NSMainThread: 0x600003fb0280>{number = 1, name = main} 2

2022-02-13 23:00:09.550822+0800 多线程[65378:1141271] <_NSMainThread: 0x600003fb0280>{number = 1, name = main} 3

2022-02-13 23:00:09.551005+0800 多线程[65378:1141271] <_NSMainThread: 0x600003fb0280>{number = 1, name = main} 4

2022-02-13 23:00:09.551148+0800 多线程[65378:1141271] 同步并发完成

同步并发:可以看到打印顺序是是按正常顺序执行,当前方法是在主线程中执行,可以看到name=main也是在主线程中执行,也就是说不具备开启线程能力,并且执行任务是一个执行完后,再执行另外一个任务。最后打印同步并发完成也是能表面同步堵塞了主线程

异步串行

dispatch_queue_t queue = dispatch_queue_create( "jj.com" , DISPATCH_QUEUE_SERIAL);

    for ( int  i = 0; i< 5; i++) {

        dispatch_async(queue, ^{

            if (i == 2) {

                sleep(2);

            }

            NSLog (@ "%@ %d" , [ NSThread  currentThread], i);

        });
    }

    NSLog (@"异步串行完成");

我们看下异步串行输出结果:

2022-02-13 22:53:23.211533+0800 多线程[63472:1133783] 异步串行完成

2022-02-13 22:53:23.211599+0800 多线程[63472:1133869] <NSThread: 0x6000025d47c0>{number = 4, name = (null)} 0

2022-02-13 22:53:23.211821+0800 多线程[63472:1133869] <NSThread: 0x6000025d47c0>{number = 4, name = (null)} 1

2022-02-13 22:53:25.212448+0800 多线程[63472:1133869] <NSThread: 0x6000025d47c0>{number = 4, name = (null)} 2

2022-02-13 22:53:25.212864+0800 多线程[63472:1133869] <NSThread: 0x6000025d47c0>{number = 4, name = (null)} 3

**2022-02-13 22:53:25.213017+0800 多线程[63472:1133869] <NSThread: 0x6000025d47c0>{number = 4, name = (null)} 4

异步串行:由上面结果,先走异步串行完成,说明异步不堵塞线程的,我们是在主线程执行代码的,看打印可以看到number = 4,说明异步串行是开启了新的线程(异步主队列是主线程中执行,不开启新线程)。

异步并发

dispatch_queue_t queue = dispatch_queue_create( "jj.com" , DISPATCH_QUEUE_CONCURRENT);

    for ( int  i = 0; i< 5; i++) {
        dispatch_async(queue, ^{
            if (i == 2) {
                sleep(2);
            }
            NSLog (@ "%@ %d" , [ NSThread  currentThread], i);
        });
    }
    NSLog (@"异步并发完成");

我们看下异步并发输出结果:

2022-02-13 23:22:47.019240+0800 多线程[2262:18916] 异步并发完成

2022-02-13 23:22:47.019361+0800 多线程[2262:21091] <NSThread: 0x600003511780>{number = 5, name = (null)} 3

2022-02-13 23:22:47.019361+0800 多线程[2262:21093] <NSThread: 0x6000035117c0>{number = 6, name = (null)} 0

2022-02-13 23:22:47.019405+0800 多线程[2262:21095] <NSThread: 0x600003510bc0>{number = 3, name = (null)} 1

2022-02-13 23:22:47.019537+0800 多线程[2262:21091] <NSThread: 0x600003511780>{number = 5, name = (null)} 4

2022-02-13 23:22:49.023048+0800 多线程[2262:21094] <NSThread: 0x600003542a40>{number = 2, name = (null)} 2

异步并发:先打印异步并发完成说明不会堵塞当前线程,打印的number各不相当,也就是说异步并发会开启新的线程,并且会并发执行任务,i==2sleep2秒,并不会影响到其它任务执行。

总结

Snipaste_2022-02-13_23-25-59.png