Java基础_多线程

news2024/9/27 7:24:59

Java基础_多线程

  • 什么是多线程
  • 并发, 并行
  • 多线程的实现方式
    • 继承Thread类
    • 实现Runnable接口
    • 实现Callable接口和Future接口
    • 实现方式对比
  • 常见的成员方法
    • 常见方法
    • 进程的优先级
    • 守护线程
    • 礼让线程
    • 插入线程
  • 线程安全
    • 线程的生命周期
    • 售票模拟
      • 同步代码块
      • 同步方法
      • lock锁
    • 死锁
  • 生产者和消费者
    • waitAndNotify
    • putAndTake
  • 线程的六种状态
  • 来源
  • Gitee地址

什么是多线程

  • 线程: 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
  • 进程: 进程是程序的基本执行实体.
  • 多线程
    • 作用: 提高效率
    • 应用场景: 软件中的耗时操作、所有的聊天软件、所有的服务器

并发, 并行

  • 并发: 在同一时刻,有多个指令在单个CPU上交替执行
  • 并行: 在同一时刻,有多个指令在多个CPU上同时执行

多线程的实现方式

继承Thread类

// TheadDemo
public class ThreadDemo01 {
    public static void main(String[] args) {
        /**
         * 多线程的第一种启动方式:
         * 1. 定义一个类继承Thread
         * 2. 重写run方法
         * 3. 创建子类的对象, 并启动线程
         */
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();

        t1.setName("thread1");
        t2.setName("thread2");

        // 开启线程
        t1.start();
        t2.start();
    }
}

// MyThread
public class MyThread extends Thread{

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName() + "Hello Thread!");
        }
    }
}

实现Runnable接口

// Demo
public class ThreadDemo {
    public static void main(String[] args) {
        /**
         * 多线程的第二种启动方式:
         * 1. 定义一个类实现Runnable接口
         * 2. 重写run方法
         * 3. 创建自己的类的对象
         * 4. 创建一个Thread类的对象, 并启动线程
         */

        // 创建MyRunnable的对象
        // 表示多线程要执行的任务
        MyRunnable myRun = new MyRunnable();

        // 创建线程对象
        Thread t1 = new Thread(myRun);
        Thread t2 = new Thread(myRun);

        t1.setName("thread1");
        t2.setName("thread2");

        // 开启线程
        t1.start();
        t2.start();
    }
}


// MyRunnable
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            // 获取当前线程的对象
            Thread t = Thread.currentThread();
            System.out.println(t.getName() + "Hello Runnable!");
        }
    }
}

实现Callable接口和Future接口

// Demo
public class Demo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /**
         * 多线程的第三种实现方式
         * 特点: 可以获取到多线程运行的结果
         *
         * 1. 创建一个类MyCallable实现Callable接口
         * 2. 重写call (有返回值, 表示多线程运行的结果)
         *
         * 3. 创建MyCallable的对象 (表示多线程要执行的任务)
         * 4. 创建FutureTask的对象 (管理多线程运行的结果)
         * 5. 创建Thread类的对象, 并启动
         */

        // 创建MyCallable的对象
        Callable myC = new MyCallable();
        // 创建FutureTask的对象
        FutureTask<Integer> myF = new FutureTask<>(myC);
        // 创建Thread类的对象
        Thread t1 = new Thread(myF);
        t1.start();

        // 获取结果
        Integer res = myF.get();
        System.out.println(res);
    }
}

// Impl
public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        // 1~100求合
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            sum += i;
        }
        return sum;
    }
}

实现方式对比

优点缺点
继承Thread类编程比较简单, 可以直接使用Thread类中的方法可扩展性较差, 不能再继承其他的类
实现Runnable接口扩展性强, 实现该接口的同时还可以继承其他的类编程相对复杂, 不能直接使用Thread类中的方法
实现Callable接口同实现Runnable接口同实现Runnable接口
  • 继承Thread类和实现Runnable接口没有返回值, 实现Callable接口可以有返回值

常见的成员方法

常见方法

// Demo
public class demo {
    public static void main(String[] args) throws InterruptedException {
        /**
         * String getName()                 返回此线程的名称
         * void setName(String name)        设置线程的名字(构造方法也可以设置名字)
         * // 线程有默认的名字
         * // 格式: Thread-x(x是序号, 从0开始)
         *
         * static Thread currentThread()    获取当前线程的对象
         * // JVM虚拟机启动后, 会自动启动多条线程,
         * // 其中有一条就叫做main线程, 它回去调用main方法
         *
         * static void sleep(long time)     让线程休眠指定的时间, 单位为毫秒
         */

        // MyThread t1 = new MyThread("飞机");
        // MyThread t2 = new MyThread("坦克");
        //
        // t1.start();
        // t2.start();

        Thread t = Thread.currentThread();
        System.out.println(t.getName()); // main

        System.out.println("111");
        Thread.sleep(3000);
        System.out.println("222");
    }
}

// Thread
public class MyThread extends Thread{

    public MyThread() {
    }

    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"@"+i);
        }
    }
}

进程的优先级

// Demo
public class Demo {
    public static void main(String[] args) {
        /**
         * setPriority(int newPriority)   设置线程的优先级
         * final int getPriority()        获取线程的优先级
         */

        MyRunnable mr = new MyRunnable();
        Thread t1 = new Thread(mr, "飞机");
        Thread t2 = new Thread(mr, "坦克");

        // 线程默认的优先级是5
        System.out.println(t1.getPriority());
        System.out.println(t2.getPriority());
        System.out.println(Thread.currentThread().getPriority());

        // 线程最大优先级是10, 最小是1
        t2.setPriority(10);
        t1.setPriority(1);

        // 优先级指定的是线程抢占到cpu的概率
        t1.start();
        t2.start();
    }
}

// runnable
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+"@"+i);
        }
    }
}

守护线程

// Demo
public class Demo {
    public static void main(String[] args) {
        /**
         * // 设置为守护线程
         * final void setDaemon(boolean on)
         * // 当其他的非守护线程执行完毕之后, 守护线程会陆续结束
         */

        MyThread1 t1 = new MyThread1();
        MyThread2 t2 = new MyThread2();

        t1.setName("女神");
        t2.setName("备胎");

        t2.setDaemon(true);

        t1.start();
        t2.start();
    }
}

// MyThread1
public class MyThread1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(getName()+"@"+i);
        }
    }
}

// MyThread2
public class MyThread2 extends Thread{

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"@"+i);
        }
    }
}

礼让线程

// Demo
public class Demo {
    public static void main(String[] args) {
        /**
         * // 出让线程/礼让线程
         * public static void yield
         * 解释: 当前占据cpu的线程执行该方法后,
         *      会让出cpu的执行权, 然后飞机和坦克会再次抢占cpu
         * 效果: 可以让线程的执行比较均衡
         */

        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();

        t1.setName("飞机");
        t2.setName("坦克");

        t1.start();
        t2.start();
    }
}

// MyThread
public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"@"+i);
            // 出让当前cpu的执行权
            Thread.yield();
        }
    }
}

插入线程

// Demo
public class Demo {
    public static void main(String[] args) throws InterruptedException {
        /**
         * // 插入线程/插队线程
         * public final void join()
         */

        MyThread t1 = new MyThread();
        t1.setName("土豆");
        t1.start();

        // 表示把t这个线程, 插入到当前线程之前
        // t: 土豆
        // 当前线程: main线程
        t1.join();

        for (int i = 0; i < 10; i++) {
            System.out.println("main线程"+i);
        }
    }
}

// MyThread
public class MyThread extends Thread{

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"@"+i);
        }
    }
}

线程安全

线程的生命周期

售票模拟

同步代码块

// Demo
public class Demo {
    public static void main(String[] args) {
        /**
         * 3个窗口模拟售卖100张票
         */

        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }
}

// MyThread
public class MyThread extends Thread{

    // 表示这个类所有的对象, 都共享ticket
    static int ticket = 0;

    // 锁对象, 一定要是唯一的
    // static Object obj = new Object();

    @Override
    public void run() {
        while(true)
        {
            // 同步代码块
            synchronized (MyThread.class){
                if(ticket >= 100){
                    break;
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                ++ticket;
                System.out.println(getName()+"正在卖第"+ticket+"张票");
            }
        }
    }
}

同步方法

// Demo
public class Demo {
    public static void main(String[] args) {
        /**
         * 3个窗口模拟售卖100张票
         */

        MyRunnable mr = new MyRunnable();

        Thread t1 = new Thread(mr);
        Thread t2 = new Thread(mr);
        Thread t3 = new Thread(mr);

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }
}

// MyRunnable
public class MyRunnable implements Runnable{

    // 只有一个Runnable对象, 不用static
    int ticket = 0;

    @Override
    public void run() {
        while(true)
        {
            if (method()) break;
        }
    }

    private synchronized boolean method() {
        if(ticket >= 1000){
            return true;
        }
        Thread t = Thread.currentThread();
        ++ticket;
        System.out.println(t.getName()+"正在卖第"+ticket+"张票");
        return false;
    }
}
  • 总结
    • 同步方法的锁对象不能自己指定, 非静态方法是this, 静态方法是当前类的字节码文件对象
    • StringBuilder是线程不安全的, StringBuffer是线程安全的(它的方法是有添加synchronized关键字)

lock锁

// Demo
public class Demo {
    public static void main(String[] args) {
        /**
         * 3个窗口模拟售卖100张票
         */

        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }
}

// MyThread
public class MyThread extends Thread{

    // 表示这个类所有的对象, 都共享ticket
    static int ticket = 0;

    static Lock lock = new ReentrantLock();

    @Override
    public void run() {
        while(true)
        {
            lock.lock();

            try {
                if(ticket >= 1000){
                    break;
                }
                Thread.sleep(1);
                ++ticket;
                System.out.println(getName()+"正在卖第"+ticket+"张票");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }

        }
    }
}
  • 总结
    • 如果简单地把解锁写在尾部, 则会导致某个线程break循环之后, 直接跳出循环而没有解锁, 导致程序不会停止

死锁

// Demo
public class Demo {
    public static void main(String[] args) {
        /**
         * 死锁
         */

        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();

        t1.setName("线程A");
        t2.setName("线程B");

        t1.start();
        t2.start();
    }
}

// MyThread
public class MyThread extends Thread{

    static Object objA = new Object();
    static Object objB = new Object();

    @Override
    public void run() {
        while(true)
        {
            if(getName().equals("线程A")){
                synchronized (objA){
                    System.out.println("线程A拿到了A锁, 准备去拿B锁");
                    synchronized (objB){
                        System.out.println("线程A拿到了B锁, 顺利执行完了一轮");
                    }
                }
            }else if(getName().equals("线程B")){

                synchronized (objB){
                    System.out.println("线程B拿到了B锁, 准备去拿A锁");
                    synchronized (objA){
                        System.out.println("线程B拿到了A锁, 顺利执行完了一轮");
                    }
                }
            }
        }
    }
}
  • 总结
    • 不要嵌套锁

生产者和消费者

waitAndNotify

// Demo
public class Demo {
    public static void main(String[] args) {
        /**
         * 实现生产者和消费者(等待唤醒机制)
         * 实现线程轮流交替执行
         */

        Cook c = new Cook();
        Foodie f = new Foodie();

        c.start();
        f.start();
    }
}

// Desk
public class Desk {

    /**
     * 控制生产者和消费者的执行
     */

    // 是否有面条  0: 没有面条,  1: 有面条
    public static int foodflag = 0;
    // 总个数
    public static int count = 10;
    // 锁对象
    public static Object lock = new Object();
}

// Cook
public class Cook extends Thread {

    @Override
    public void run() {
        while(true)
        {
            synchronized (Desk.lock){
                if(Desk.count == 0){
                    break;
                }else{
                    // 判断桌子上是否有食物
                    if(Desk.foodflag == 1){
                        // 如果有, 就等待
                        System.out.println("还有, 不做");
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }else{
                        // 如果没有, 就制作食物
                        System.out.println("厨师做了一碗面条");
                        // 修改桌子上的食物状态
                        Desk.foodflag = 1;
                        // 叫醒等待的消费者开吃
                        Desk.lock.notifyAll();
                    }
                }
            }
        }
    }
}

// Foodie
public class Foodie extends Thread{
    
    @Override
    public void run() {
        while(true)
        {
            synchronized (Desk.lock){
                if(Desk.count == 0){
                    break;
                }else{
                    // 先判断桌子上是否有面条
                    if(Desk.foodflag == 0){
                        // 如果没有, 就等待
                        System.out.println("没得吃");
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }else{
                        // 把吃的总数-1
                        Desk.count -= 1;
                        // 如果有, 就开吃
                        System.out.println("吃货正在吃面条, 还能吃"+Desk.count+"碗");
                        // 吃完之后, 唤醒厨师继续做
                        Desk.lock.notifyAll();
                        // 修改桌子的状态
                        Desk.foodflag = 0;
                    }
                }
            }
        }
    }
}

putAndTake

// Demo
public class Demo {
    public static void main(String[] args) {
        /**
         * 阻塞队列实现生产者和消费者(等待唤醒机制)
         */

        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);

        Cook c = new Cook(queue);
        Foodie f = new Foodie(queue);

        c.start();
        f.start();
    }
}

// Cook
public class Cook extends Thread {

    ArrayBlockingQueue<String> queue;

    public Cook(ArrayBlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        while(true)
        {
            try {
                queue.put("面条");
                System.out.println("厨师放了一碗面条");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

// Foodie
public class Foodie extends Thread{

    ArrayBlockingQueue<String> queue;

    public Foodie(ArrayBlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        while(true)
        {
            try {
                String take = queue.take();
                System.out.println("吃货拿了一碗"+take);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
  • 总结
    • 输出语句在锁外面, 导致打印顺序会有问题

线程的六种状态

  • 新建状态 (New) -> 创建线程对象
  • 就绪状态 (Runnable) -> start方法
  • 阻塞状态 (Blocked) -> 无法获得锁对象
  • 等待状态 (Waiting) -> wait方法
  • 计时等待 (Timed_Waiting) -> sleep方法
  • 结束状态 (Terminated) -> 全部代码运行完毕
  • 运行状态: 该状态交给操作系统管理, 没有定义

来源

黑马程序员. 阿玮Java零基础

Gitee地址

https://gitee.com/yu-ba-ba-ba/awJava

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/805372.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C语言】通讯录1.0 (静态版)

前言 通讯录是一种记录联系人信息的工具&#xff0c;包括姓名、电话号码、电子邮件地址、住址等。 此通讯录是基于自定义类型的基础上进行制作&#xff0c;通讯录&#xff08;静态版&#xff09;&#xff0c;后期会进行通讯录的更新 ****** 有需要源代码&#xff0c;见文章末尾…

大于号在python中怎么打,python大于等于怎么写

大家好&#xff0c;小编为大家解答python中大于并小于一个数代码的问题。很多人还不知道python中大于等于且小于等于&#xff0c;现在让我们一起来看看吧&#xff01; 1、python 中不等于怎么表示 #!/usr/bin/python a1 b2 if ab: print "a 等于 b" if a!b: print &…

ArcGIS Pro 制作一张立体地形图

在各位关掉文章之前,先把成果贴上来 下面开始操作步骤贴图,这个真的很简单,没有什么复杂的软件联动和操作 这是哥斯达黎加部分区域的30mDEM,数据链接我放在最后。 首先,找到工具【栅格函数】—【统计分析】,选择下载好的栅格,领域设置行列数都改为6,点击创建新图层。然…

从官网认识 JDK,JRE,JVM 三者的关系

点击下方关注我&#xff0c;然后右上角点击...“设为星标”&#xff0c;就能第一时间收到更新推送啦~~~ JVM 是一些大厂面试必问点&#xff0c;要想解决 OOM、性能调优方面的问题&#xff0c;掌握 JVM 知识必不可少&#xff0c;从今天开始&#xff0c;将为大家介绍 JVM 的常用知…

ShardingSphere Pipeline 兼容 MySQL 时间类型 解读

背景 ShardingSphere 在日常中&#xff0c;开发者经常会用到时间类型&#xff0c;如果熟悉的时间类型涉及到了时区、精度&#xff0c;哪种时间类型更合适&#xff1f;JDBC 驱动中又有哪些注意事项&#xff1f;因此&#xff0c;对数据库时间类型有更深入的了解&#xff0c;有助于…

android framework车载桌面CarLauncher的TaskView详细源码分析

1、构建相关的TaskView&#xff0c;装载到对应的ViewGroup b站免费视频教程讲解&#xff1a; https://www.bilibili.com/video/BV1wj411o7A9/ //packages/apps/Car/Launcher/src/com/android/car/carlauncher/CarLauncher.java void onCreate() { //ignoresetContentView(R.…

管理类联考——写作——记忆篇——论证有效性分析——析错口诀

析错口诀 概念不明确&#xff0c;我就说它概念模糊&#xff0c;并做不利它的解释。【有概念模糊之嫌&#xff0c;A是理解1&#xff1f;还是理解2&#xff1f;】概念有变换&#xff0c;我就说它混淆概念&#xff0c;并指出混淆的环节。&#xff08;概念推概念&#xff0c;我就看…

类方法(成员方法)与构造方法的区别与联系

&#xff08;粗略理解为&#xff1a;除了构造方法以外的所有方法都是成员方法&#xff09; 区别&#xff1a; 构造方法在创建对象时用new调用&#xff0c;是为了给对象的数据进行初始化&#xff0c;没有返回值。 成员方法是实现对类中成员变量的操作&#xff0c;提供某些功能…

【图论】kruskal算法

一.介绍 Kruskal&#xff08;克鲁斯卡尔&#xff09;算法是一种用于解决最小生成树问题的贪心算法。最小生成树是指在一个连通无向图中&#xff0c;选择一棵包含所有顶点且边权重之和最小的树。 下面是Kruskal算法的基本步骤&#xff1a; 将图中的所有边按照权重从小到大进行…

JUC并发工具类

一、ReentrantLock 特点&#xff1a;独占、可重入、公平/非公平、可中断、支持多个条件变量 1、常用api ReentrantLock实现了Lock接口&#xff0c;Lock类规范定义了如下方法 lock()&#xff1a;获取锁&#xff0c;调用该方法的线程会获取锁&#xff0c;当锁获得后&#xff0…

想做上位机,学C#还是QT?

学习C#还是Qt&#xff0c;取决于你的具体需求和偏好。 如果你计划开发跨平台的桌面应用程序&#xff0c;并且希望使用一种更轻量级、直观的界面框架&#xff0c;那么Qt可能是一个不错的选择。Qt是一个功能丰富且成熟的跨平台框架&#xff0c;支持多种开发语言&#xff08;包括…

第J2周:ResNet50V2算法实战与解析

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f366; 参考文章&#xff1a;365天深度学习训练营-第J2周&#xff1a;ResNet50V2算法实战与解析&#x1f356; 原作者&#xff1a;K同学啊|接辅导、项目定制 目录 一、论文解读1. ResNetV2结构与…

【需求响应】一种新的需求响应机制DR-VCG研究

目录 1 主要内容 2 部分代码 3 程序结果 4 程序链接 1 主要内容 该程序对应文章《Contract Design for Energy Demand Response》&#xff0c;电力系统需求响应&#xff08;DR&#xff09;用来调节用户对电能的需求&#xff0c;即在预测的需求高于电能供应时&#xff0c;希…

VS Code调试Darknet

一、安装插件 二、连接服务器 三、调试darknet工程 {"version": "2.0.0","options": {"cwd": "${workspaceFolder}"},"tasks": [{"label": "clean","type": "shell",&qu…

数据结构之动态顺序表(附带完整程序)

&#x1f388;基本概念 &#x1f308;一.线性表、顺序表的定义 ☀️&#xff08;1&#xff09;线性表&#xff1a; 是n个具有相同特性的数据元素的有限序列。线性表在逻辑上是线性结构&#xff0c;但在物理上存储时&#xff0c;通常以数组和链式结构的形式存储。 ☀️&…

C# 关于使用newlife包将webapi接口寄宿于一个控制台程序、winform程序、wpf程序运行

C# 关于使用newlife包将webapi接口寄宿于一个控制台程序、winform程序、wpf程序运行 安装newlife包 Program的Main()函数源码 using ConsoleApp3; using NewLife.Log;var server new NewLife.Http.HttpServer {Port 8080,Log XTrace.Log,SessionLog XTrace.Log }; serv…

hcip——ospf综合

要求 1. 搭建toop 2.地址规划 协议范围路由器地址 RIP 172.16.0.0 17 R12 loop0&#xff1a;172.16.0.0 24 loop1&#xff1a;172.16.1.0 24 OSPF 172.16.128.0 17 area1 172.16.144.0 20 R1 g0:172.16.144.1 24 loop0:172.16.145.1 24 R2 g0:172.16.144.2 24 loop:172…

iOS - Apple开发者账户添加新测试设备

获取UUID 首先将设备连接XCode&#xff0c;打开Window -> Devices and Simulators&#xff0c;通过下方位置查看 之后登录(苹果开发者网站)[https://developer.apple.com/account/] &#xff0c;点击设备 点击加号添加新设备 填写信息之后点击Continue&#xff0c;并一路继续…

Golang Devops项目开发(1)

1.1 GO语言基础 1 初识Go语言 1.1.1 开发环境搭建 参考文档&#xff1a;《Windows Go语言环境搭建》 1.2.1 Go语言特性-垃圾回收 a. 内存自动回收&#xff0c;再也不需要开发人员管理内存 b. 开发人员专注业务实现&#xff0c;降低了心智负担 c. 只需要new分配内存&#xff0c;…

Android系统服务之AMS

目录 概述 重点和难点问题 启动方式 main入口&#xff1a; run方法&#xff1a; BootstrapSevices 小结&#xff1a; 与其他线程的通信原理 参考文档&#xff1a; 概述 AMS是Android系统主要负责四大组件的启动&#xff0c;切换&#xff0c;调度以及应用程序进程管理和调度等工…