从Android面试题目溯源-1、创建线程有那几种方式

概念

程序执行流的最小单位,处理器调度调度和分派的基本单位。

如何理解这个概念

如下图,可以简单类比吉他,六根弦代表六个线程,每个线程独立且单独运行,且持有上一个音的状态,每根手指可类比为一个CPU的核心,在Arm架构中,大小核架构可以类比吉他的高底音弦,震动频率高的1,2,3弦为大核,震动频率相对较低的4,5,6弦为小核(之后针对Arm架构单独讨论)

Java的创建方式

  1. 继承Thread
  2. 实现Runnable
  3. 匿名内部类实现Runnable接口
  4. 使用Callable和Future创建有返回值的线程

延伸

Dart如何创建并管理线程

Dart线程模型基于事件循环(event loop)和异步编程的理念,通过Steam和Future类型来支持异步编程。真正意义上的线程被称为Isolate,对应Java意义上的线程,我们可以简单类比Android的Handler-Looper机制为展开版本的async, await,Future异步模型,两者都是基于事件循环,同样的模式,在kotlin等其他语言中可能被称为协程

Rust如何创建并管理线程

  1. 使用std::thread::spawn函数
  2. 使用std::thread::Builder

Linux编程中线程的概念

当我们将目光深入到Linux系统中,我们会发现Linux系统使用轻量级进程(LWP,Lightweight Process)的线程模型来实现多线程,怎么来理解这句话,首先是和进程类似,或者说包含进程的性质的同时,又是轻量级,从具体实现上,我们知晓轻量是指,共享进程的资源(地址空间,文件描述符和其他操作系统资源)。

  • pthread_create创建线程
  • pthread_exit退出线程
  • pthread_cancel取消线程

我们从Linux的编程的概念当中可以看出,虚拟机线程的实现是依赖于操作系统的实现,大部分情况下,语言创建线程对应操作系统的线程,他们有对应关系。

Linux操作系统如何创建线程

计算机组成原理中,我们知晓计算机基本构成,CPU负责计算,内存负责存储计算数据,在Arm架构中,RISC(精简指令集)使用的便是load/save内存操作模型,计算机数据特定的约定可以解释为特定的含义。我们带着这个观点去查看一下Linux使用Syscall(系统调用)创建线程的过程。

c 复制代码
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

void child_function(void *arg) {
    // 新线程执行的代码
    printf("Child thread: %s\n", (char *)arg);
}

int main() {
    // 创建一个新的栈空间
    char stack[4096];
    
    // 使用 clone 系统调用创建新线程
    int flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS;
    pid_t child_pid = clone(child_function, stack + sizeof(stack), flags, "Hello from child thread");

    if (child_pid == -1) {
        perror("clone");
        exit(EXIT_FAILURE);
    }

    // 主线程执行的代码
    printf("Main thread\n");

    // 等待新线程结束
    waitpid(child_pid, NULL, 0);

    return 0;
}

我们看到通过系统调用clone, 我们得到一个新的,栈大小为4096个字节的线程,新线程栈底部方法是child_function, 其中,创建线程的参数flag 表示共享的资源,例如虚拟内存空间CLONE_VM

总结

回到面试题,线程的创建和管理是开辟一个新的方法栈空间,执行新的函数调用。最初的原因是 IO性能远远低于CPU处理性能,在客户端上的体现是不耗时操作不阻塞主线程(UI线程)给用户提供流畅的体验,近些年来,协程的出现,本质上是Event Loop + 异步编程,轻量级的协程,优化的事件队列,比如Flutter实现的EventLoop由两部分组成。

  • 事件队列(Event Queue),存储异步事件
  • 微任务队列(Microtask Queue)存储立即执行的异步事件

这些方式都非常适合客户端提高流畅性和响应速度,可以多使用协程等类似的手段处理小并发问题,性能上会优于使用线程。

相关推荐
indexsunny9 小时前
互联网大厂Java求职面试实战:微服务与Spring生态全攻略
java·数据库·spring boot·安全·微服务·面试·消息队列
心软小念10 小时前
金三银四,全网最详细的软件测试面试题总结
软件测试·面试·职场和发展
Wilber的技术分享11 小时前
【LeetCode高频手撕题 2】面试中常见的手撕算法题(小红书)
笔记·算法·leetcode·面试
软件测试媛12 小时前
软件测试常见的面试题(46道)
功能测试·面试·职场和发展
东离与糖宝14 小时前
金三银四Java校招面经:从双非到大厂Offer,我只准备了这些
java·面试
红云梦15 小时前
简历投了 100 份没回音?我给面试平台加了个“简历雷达“
人工智能·面试·职场和发展
星辰_mya16 小时前
InnoDB的“身体结构”:页、Buffer Pool与Redo Log的底层奥秘
数据库·mysql·spring·面试·系统架构
iPadiPhone16 小时前
分布式架构的“润滑剂”:RabbitMQ 核心原理与大厂面试避坑指南
分布式·后端·面试·架构·rabbitmq
kyriewen16 小时前
DOM树与节点操作:用JS给网页“动手术”
前端·javascript·面试
郝学胜-神的一滴16 小时前
【技术实战】500G单行大文件读取难题破解!生成器+自定义函数最优方案解析
开发语言·python·程序人生·面试