【Jetpack 之 Lifecycle】

news2024/9/24 23:25:23

Jetpack 之 Lifecycle

在本系列文章中,我们准备分析Jetpack 架构组件。首先我们从最基础的组件开始: Lifecycle, 可以说Jetpack 大部分架构组件都是基于Lifecycle 建立的,此也为Jetpack 架构组件的基础。

关于此此组件的介绍和简单使用方法,这里就不做过多介绍了,不清楚的可以直接看官方文档 :传送门

我们这里主要通过代码结构来分析下组件设计和结构,先来看下Lifecycle的主要类关系图:
图一以上类图基本阐释了Lifecycle组件之间的关系,也是Lifecycle这个组件的本质的设计原理。从结构设计来看,这个设计主要就是基于观察者模式,比较简洁明了,相信大部分有设计模式经验的人看图就了解了Lifecycle的设计意图和结构。 那么,设计思想和结构有了,我们接下来就来看看在Android 中 是如何实现的。

Lifecycle 之 LifecycleRegistry

我们知道观察者模式的三个主要步骤:添加观察者,删除观察者,变更状态通知观察者

由图一看出LifecycleRegistry类实现了Lifecycle 接口,那接下来我们就来看看LifecycleRegistry的实现。
我们想要观察一个Lifecycle,应该是调用LifecycleaddObserver方法,那我们就到LifecycleResgistry中看看addObserver方法是如何实现的:

添加观察者

(下面我们看主要流程,其他细节先忽略,主要流程添加中文注释)

    @Override
    public void addObserver(@NonNull LifecycleObserver observer) {
        enforceMainThreadIfNeeded("addObserver");
    //初始化state
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
    //1.  new 一个ObserverWithState对象,包含传入的Observer和初始状态state
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
    //把刚才new出来的对象放入OberverMap中
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

	//如果Observer已经加入过了, 直接返回
        if (previous != null) {
            return;
        }
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            // it is null we should be destroyed. Fallback quickly
            return;
        }

	//判断是否重复进入, 判断条件后面介绍
        boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
    //2.  计算目标状态,计算规则后面看
        State targetState = calculateTargetState(observer);
    //记录当天处于addingObersver状态
        mAddingObserverCounter++;
    //当加入的Oberver的状态小于本Lifecycle的状态时
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
    //把当前状态作为parent状态入栈(如果在adding的时候,lifecycle的状态更新了, 或者反之, 计算目标状态的时候使用)
            pushParentState(statefulObserver.mState);
   	//获取当前状态的up Event
            final Event event = Event.upFrom(statefulObserver.mState);
            if (event == null) {
                throw new IllegalStateException("no event up from " + statefulObserver.mState);
            }
     //3.  dispatch Event
            statefulObserver.dispatchEvent(lifecycleOwner, event);
     //出栈Parent状态
            popParentState();
            // mState / subling may have been changed recalculate
    //重新计算目标状态
            targetState = calculateTargetState(observer);
        }
	//如果不是重入,则同步
        if (!isReentrance) {
            // we do sync only on the top level.
            sync();
        }
        mAddingObserverCounter--;
    }

好,那我么再来看看1处的OberverWithState是个什么东东:

    static class ObserverWithState {
        State mState;
        LifecycleEventObserver mLifecycleObserver;

        ObserverWithState(LifecycleObserver observer, State initialState) {
            mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
            mState = initialState;
        }

        void dispatchEvent(LifecycleOwner owner, Event event) {
            State newState = event.getTargetState();
            mState = min(mState, newState);
            mLifecycleObserver.onStateChanged(owner, event);
            mState = newState;
        }
    }

嗯, 这里就是对LifecycleObserver 和 其当状态的一个封装。这里有一个很特别的类Lifecycling, 它其实就是把我们用各种方式实现的LifecycleObserver进行统一的封装管理,都封装成LifecycleEventObserver类型,以便下面dispatchEvent统一调用。
好,我们继续来看dispatchEvent
dispatchEvent很简单,就是根据Event找到对应的状态,然后设置为当前Observer的状态,然后分发事件给Observer的实现类,然后再结合addObserver23 处)时的循环计算目前状态然后分发,就可以实现Observer事件的有序性,就是不会一上来就只分发个最终状态,所以Observer接受的事件一定是有序的,如官方文档的图:
在这里插入图片描述
状态和事件只能是沿着箭头方向顺序的进行,不能跳过。

删除观察者

删除就很简单了,这里就不跟踪了。

状态变更通知

再回过头来看下LifecycleRegistery类, 涉及到状态变更的public方法只有makeStatesetCurrentState, 和handleLifecycleEvent三个,而且这三个类都是调用moveToState方法改变状态的,那我们就来看看moveToState方法。

private void moveToState(State next) {
        if (mState == next) {
            return;
        }
    //变更当前被观察者状态
        mState = next;
    //如果正在变更或者正在添加观察者,设置标记新时间发生,然后直接退出
        if (mHandlingEvent || mAddingObserverCounter != 0) {
            mNewEventOccurred = true;
            // we will figure out what to do on upper level.
            return;
        }
    //标记正在处理事件,然后同步
        mHandlingEvent = true;
        sync();
        mHandlingEvent = false;
    }

我们接着看同步:

// happens only on the top of stack (never in reentrance),
    // so it doesn't have to take in account parents
    private void sync() {
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"
                    + "garbage collected. It is too late to change lifecycle state.");
        }
    //没有同步好就继续同步,同步好的判断:最前,最后观察者的状态和被观察者的状态一致
        while (!isSynced()) {
    //开始同步,清除新事件标记
            mNewEventOccurred = false;
            // no need to check eldest for nullability, because isSynced does it for us.
            if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
    //从后方前更新状态
                backwardPass(lifecycleOwner);
            }
            Map.Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
            if (!mNewEventOccurred && newest != null
                    && mState.compareTo(newest.getValue().mState) > 0) {
   //从前向后更新状态
                forwardPass(lifecycleOwner);
            }
        }
        mNewEventOccurred = false;
    }

好了,到这里我们就大体了解了LifecycleRegistery对观察者模式实现的基本过程,那么,现在问题有来了,是谁,怎么更新的LifecycleRegistery的状态呢?

Lifecycle 之 状态更新

搜索LifecycleRegistryhandleLifecycleEvent方法调用,发现只在AndroidX.Fragment的生命周期函数中调用了,在AndroidX的一系列Activity类的生命周期中没有发现调用,那么Activity的Lifecycle状态更新是何时调用的呢?

经过搜索发现了一个叫ReportFragment的类里面有关于Activity的getLifecycle().handleLifecycleEvent(event)调用,那我们就来研究下 这个ReprotFragment

我们发现在这个fragment中的生命周期函数中都调用了相应dispatch方法进行Lifecycle 事件分发,那么这个Fragment是如何与Activity关联的呢?

我们就发现了injectIfNeededIn这个静态方法:

public static void injectIfNeededIn(Activity activity) {
        if (Build.VERSION.SDK_INT >= 29) {
            // On API 29+, we can register for the correct Lifecycle callbacks directly
            LifecycleCallbacks.registerIn(activity);
        }
        // Prior to API 29 and to maintain compatibility with older versions of
        // ProcessLifecycleOwner (which may not be updated when lifecycle-runtime is updated and
        // need to support activities that don't extend from FragmentActivity from support lib),
        // use a framework fragment to get the correct timing of Lifecycle events
        android.app.FragmentManager manager = activity.getFragmentManager();
        if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
            manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();
            // Hopefully, we are the first to make a transaction.
            manager.executePendingTransactions();
        }
    }

其作用就是把它加入到Activity的FragmentMananger中。经过引用链接,我们发现了在ComponentActivityonCreate方法中调用了此函数:

protected void onCreate(@Nullable Bundle savedInstanceState) {
        // Restore the Saved State first so that it is available to
        // OnContextAvailableListener instances
        mSavedStateRegistryController.performRestore(savedInstanceState);
        mContextAwareHelper.dispatchOnContextAvailable(this);
        super.onCreate(savedInstanceState);
        ReportFragment.injectIfNeededIn(this);
        if (mContentLayoutId != 0) {
            setContentView(mContentLayoutId);
        }
    }

由于Fragment的生命周期是跟着Actiivty走的,所以我们监听了Fragment的生命周期,也就相当于监听了Activity的生命周期,至此我们AndroidX系列的Activity生命周期也纳入了Lifecycle的监听范围。

至此,LifecycleRegetry的跟踪应该结束了,但是大家是否有个疑问,为什么不直接在Activity的生命周期函数中分发事件,而要用一个ReportFragment呢?参考应用文章中的解释:

因为不是所有的页面都继承AppCompatActivity,为了兼容非AppCompatActivity,所以封装一个同样具有生命周期的Fragment来给Lifecycle分发生命周期事件。

好,那么非AppCompatActivity中是如何监听生命周期的呢?我们又搜索到了ReportFragment的另一个使用地方LifecycleDispatcher

class LifecycleDispatcher {

    private static AtomicBoolean sInitialized = new AtomicBoolean(false);

    static void init(Context context) {
        if (sInitialized.getAndSet(true)) {
            return;
        }
        ((Application) context.getApplicationContext())
                .registerActivityLifecycleCallbacks(new DispatcherActivityCallback());
    }

    @SuppressWarnings("WeakerAccess")
    @VisibleForTesting
    static class DispatcherActivityCallback extends EmptyActivityLifecycleCallbacks {

        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            ReportFragment.injectIfNeededIn(activity);
        }

        @Override
        public void onActivityStopped(Activity activity) {
        }

        @Override
        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        }
    }

    private LifecycleDispatcher() {
    }
}

这里是通过注册activity周期回调,当新建一个Activity的时候,就将ReportFragment添加进去,当然必须是FragmentActivity。

好,之前搜索的时候,我们还搜到了另一处使用reportFragment的地方ProcessLifecycleOwner

public class ProcessLifecycleOwner implements LifecycleOwner {

    @VisibleForTesting
    static final long TIMEOUT_MS = 700; //mls

    // ground truth counters
    private int mStartedCounter = 0;
    private int mResumedCounter = 0;

    private boolean mPauseSent = true;
    private boolean mStopSent = true;

    private Handler mHandler;
    private final LifecycleRegistry mRegistry = new LifecycleRegistry(this);

    private Runnable mDelayedPauseRunnable = new Runnable() {
        @Override
        public void run() {
            dispatchPauseIfNeeded();
            dispatchStopIfNeeded();
        }
    };

    ActivityInitializationListener mInitializationListener =
            new ActivityInitializationListener() {
                @Override
                public void onCreate() {
                }

                @Override
                public void onStart() {
                    activityStarted();
                }

                @Override
                public void onResume() {
                    activityResumed();
                }
            };

    private static final ProcessLifecycleOwner sInstance = new ProcessLifecycleOwner();

    /**
     * The LifecycleOwner for the whole application process. Note that if your application
     * has multiple processes, this provider does not know about other processes.
     *
     * @return {@link LifecycleOwner} for the whole application.
     */
    @NonNull
    public static LifecycleOwner get() {
        return sInstance;
    }

    static void init(Context context) {
        sInstance.attach(context);
    }

    void activityStarted() {
        mStartedCounter++;
        if (mStartedCounter == 1 && mStopSent) {
            mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
            mStopSent = false;
        }
    }

    void activityResumed() {
        mResumedCounter++;
        if (mResumedCounter == 1) {
            if (mPauseSent) {
                mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
                mPauseSent = false;
            } else {
                mHandler.removeCallbacks(mDelayedPauseRunnable);
            }
        }
    }

    void activityPaused() {
        mResumedCounter--;
        if (mResumedCounter == 0) {
            mHandler.postDelayed(mDelayedPauseRunnable, TIMEOUT_MS);
        }
    }

    void activityStopped() {
        mStartedCounter--;
        dispatchStopIfNeeded();
    }

    void dispatchPauseIfNeeded() {
        if (mResumedCounter == 0) {
            mPauseSent = true;
            mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
        }
    }

    void dispatchStopIfNeeded() {
        if (mStartedCounter == 0 && mPauseSent) {
            mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
            mStopSent = true;
        }
    }

    private ProcessLifecycleOwner() {
    }

    @SuppressWarnings("deprecation")
    void attach(Context context) {
        mHandler = new Handler();
        mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
        Application app = (Application) context.getApplicationContext();
        app.registerActivityLifecycleCallbacks(new EmptyActivityLifecycleCallbacks() {
            @RequiresApi(29)
            @Override
            public void onActivityPreCreated(@NonNull Activity activity,
                    @Nullable Bundle savedInstanceState) {
                // We need the ProcessLifecycleOwner to get ON_START and ON_RESUME precisely
                // before the first activity gets its LifecycleOwner started/resumed.
                // The activity's LifecycleOwner gets started/resumed via an activity registered
                // callback added in onCreate(). By adding our own activity registered callback in
                // onActivityPreCreated(), we get our callbacks first while still having the
                // right relative order compared to the Activity's onStart()/onResume() callbacks.
                Api29Impl.registerActivityLifecycleCallbacks(activity,
                        new EmptyActivityLifecycleCallbacks() {
                            @Override
                            public void onActivityPostStarted(@NonNull Activity activity) {
                                activityStarted();
                            }

                            @Override
                            public void onActivityPostResumed(@NonNull Activity activity) {
                                activityResumed();
                            }
                        });
            }

            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                // Only use ReportFragment pre API 29 - after that, we can use the
                // onActivityPostStarted and onActivityPostResumed callbacks registered in
                // onActivityPreCreated()
                if (Build.VERSION.SDK_INT < 29) {
                    ReportFragment.get(activity).setProcessListener(mInitializationListener);
                }
            }

            @Override
            public void onActivityPaused(Activity activity) {
                activityPaused();
            }

            @Override
            public void onActivityStopped(Activity activity) {
                activityStopped();
            }
        });
    }

    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return mRegistry;
    }

    @RequiresApi(29)
    static class Api29Impl {
        private Api29Impl() {
            // This class is not instantiable.
        }

        @DoNotInline
        static void registerActivityLifecycleCallbacks(@NonNull Activity activity,
                @NonNull Application.ActivityLifecycleCallbacks callback) {
            activity.registerActivityLifecycleCallbacks(callback);
        }
    }
}

由以上代码可知,ProcessLifecycleOwner是进程生命周期的拥有者,通过应用的Actiivt引用计数,当第一个Activity 创建的时候,状态变更为CREATED, 当最后一个Activity Stop的时候,状态变更为STOPPED。

好了,那么以上两个类自己本身又是再那里生成的呢?

然后我们就搜到了ProcessLifecycleInitializer 这个类:

public final class ProcessLifecycleInitializer implements Initializer<LifecycleOwner> {

    @NonNull
    @Override
    public LifecycleOwner create(@NonNull Context context) {
        AppInitializer appInitializer = AppInitializer.getInstance(context);
        if (!appInitializer.isEagerlyInitialized(getClass())) {
            throw new IllegalStateException(
                    "ProcessLifecycleInitializer cannot be initialized lazily. \n"
                            + "Please ensure that you have: \n"
                            + "<meta-data\n"
                            + "    android:name='androidx.lifecycle.ProcessLifecycleInitializer' \n"
                            + "    android:value='androidx.startup' /> \n"
                            + "under InitializationProvider in your AndroidManifest.xml");
        }
        LifecycleDispatcher.init(context);
        ProcessLifecycleOwner.init(context);
        return ProcessLifecycleOwner.get();
    }

    @NonNull
    @Override
    public List<Class<? extends Initializer<?>>> dependencies() {
        return Collections.emptyList();
    }
}

它是一个Initializer, 具体可以参考:传送门
它在应用初始化的时候被调用,在包的AndroidManiest中注册:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="androidx.lifecycle.process" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="31" />

    <application>
        <provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            android:exported="false"
            tools:node="merge" >
            <meta-data
                android:name="androidx.lifecycle.ProcessLifecycleInitializer"
                android:value="androidx.startup" />
        </provider>
    </application>

</manifest>

这样就把组件加入到了启动组件中,对了,要使用的话,需要引入:

androidx.lifecycle:lifecycle-process:$vesion

结语

Lifecycle组件相关的分析就到这里了,接下来我们会继续分析其他的Jetpack 架构组件
欢迎大家交流,如果喜欢的话,也可以点歌关注和赞哦

参考文章:
Android-Lifecycle超能解析-生命周期的那些事儿
Lifecycle 使用及原理解析 一文搞懂

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

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

相关文章

回答网友 修改一个exe

网友说&#xff1a;他有个很多年前的没有源码的exe&#xff0c;在win10上没法用&#xff0c;让俺看一下。 俺看了一下&#xff0c;发现是窗体设计的背景色的问题。这个程序的背景色用的是clInactiveCaptionText。clInactiveCaptionText 在win10之前的系统上是灰色&#xff0c;但…

【Ajax】笔记-原生jsonp跨域请求案例

原生jsonp跨域请求 输入框&#xff1a;输入后&#xff0c;鼠标移开向服务端发送请求&#xff0c;返回用户不存在(直接返回不存在&#xff0c;不做判断) JS <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><me…

ubuntu22.04 DNSSEC(加密DNS服务) configuration

/etx/systemd/resolved.conf是ubuntu下DNS解析服务配置文件&#xff0c;systemd为ubuntu下system and service配置目录 step 1——修改resolved.conf参数 管理员权限打开 /systemd/resolved.conf sudo nano /etc/systemd/resolved.conf修改如下&#xff1a; # This file i…

17-C++ 数据结构 - 栈

&#x1f4d6; 1.1 什么是栈 栈是一种线性数据结构&#xff0c;具有后进先出&#xff08;Last-In-First-Out&#xff0c;LIFO&#xff09;的特点。可以类比为装满盘子的餐桌&#xff0c;每次放盘子都放在最上面&#xff0c;取盘子时也从最上面取&#xff0c;因此最后放进去的盘…

68. 文本左右对齐

题目链接&#xff1a;力扣 解题思路&#xff1a;遍历单词数组&#xff0c;确定每一行的单词数量&#xff0c; 之后就可以得到每一个需要补充的空格数量。从而得到单词之间需要补充的空格数量。具体算法如下&#xff1a; 确定每一行的单词数量 初始值&#xff1a; num 0&…

基于springboot+mybatis+jsp日用品商城管理系统

基于springbootmybatisjsp日用品商城管理系统 一、系统介绍二、功能展示1.主页(客户)2.登陆、注册&#xff08;客户&#xff09;3.我的购物车(客户)4.我的订单&#xff08;客户&#xff09;5.我的商铺&#xff08;商家&#xff09;6.商品管理&#xff08;商家&#xff09;7.订单…

【编程规范】一文讲解开发中的命名规范

命名规范 好的代码本身就是注释, 所以我们需要统一命名风格。 ​ 在本文中&#xff0c;将从大到小&#xff0c;从外到内&#xff0c;总结Java编程中的命名规范。文中将会涉及到日常工作中常见的命名示例&#xff0c;如包命名&#xff0c;类命名&#xff0c;接口命名&#xff0c…

计算机网络——学习笔记

付费版&#xff1a;直接在上面的CSDN资源下载 免费版&#xff1a;https://wwsk.lanzouk.com/ijkcj13tqmyb 示例图&#xff1a;

BIOS相关知识

简介 BIOS&#xff08;Basic Input Output System&#xff09;基本输入输出系统&#xff0c;固化在服务器主板的专用ROM中&#xff0c;是加载在服务器硬件系统上最基本的运行程序。BIOS位于硬件和系统中间&#xff0c;用来初始化硬件&#xff0c;为操作系统运行做准备 功能 …

C语言进阶——文件的打开(为什么使用文件、什么是文件、文件的打开和关闭)

目录 为什么使用文件 什么是文件 程序文件 数据文件 文件名 文件的打开和关闭 文件指针 打开和关闭 为什么使用文件 在之前学习通讯录时&#xff0c;我们可以给通讯录中增加、删除数据&#xff0c;此时数据是存放在内存中&#xff0c;当程序退出的时候&#xff0c;通讯…

【算法提高:动态规划】1.1 数字三角形模型

文章目录 例题列表1015. 摘花生1018. 最低通行费1027. 方格取数&#xff08;两条路径同时走&#xff09;⭐⭐⭐⭐⭐275. 传纸条&#xff08;转换成 两条路径同时走&#xff09; 例题列表 1015. 摘花生 https://www.acwing.com/problem/content/1017/ 状态要么从左转移过来&…

基于双层优化的大型电动汽车时空调度(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

❤️创意网页:贪吃蛇游戏 - 创造一个经典的小游戏

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…

c++的函数定义中,只提供形参类型,不提供形参名

如上图所示&#xff0c;显示了 c 语法里的一种不常见的应用。若没有对某个形参的后续使用的要求&#xff0c;可以不提供形参名的&#xff0c;也能编译通过。这么写法的作用&#xff0c;可以以第一个参数的类型不同&#xff0c;来实现函数的重载。在阅读源码&#xff0c;在vs201…

【Linux】UDP协议

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《学会Linux》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录 &#x1f449;传输层&a…

目标检测应用场景—数据集【NO.14】行人跌倒测试

写在前面&#xff1a;数据集对应应用场景&#xff0c;不同的应用场景有不同的检测难点以及对应改进方法&#xff0c;本系列整理汇总领域内的数据集&#xff0c;方便大家下载数据集&#xff0c;若无法下载可关注后私信领取。关注免费领取整理好的数据集资料&#xff01;今天分享…

什么是线程?线程和进程的关系?如何创建/查看线程?

文章目录 一. 认识线程(Thread)1.1 概念1.1.1 什么是线程1.1.2 线程存在的意义1.1.3 进程和线程之间的区别和联系1.1.4 Java的线程和操作系统的线程 1.2 创建线程① 继承Thread类② 实现Runnable 接口对比两种方法③ 变形写法④ 其他写法 1.3 查看线程 一. 认识线程(Thread) 1…

C++之科学技术法e使用(一百七十二)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

阿里云服务器全方位介绍_性能功能优势和租用费用

阿里云服务器全方位介绍包括云服务器ECS优势、云服务器租用价格、云服务器使用场景及限制说明&#xff0c;阿里云服务器网分享云服务器ECS介绍、个人和企业免费试用、云服务器活动、云服务器ECS规格、优势、功能及应用场景详细说明&#xff1a; 目录 什么是云服务器ECS&#…

学习笔记22 set

一、概述 Set是一种集合类型&#xff0c;可以快速在大量数据中查找特定值。 Set存储无序序列中的元素&#xff0c;并且不允许重复。与列表不同&#xff0c;列表中的数据可以通过索引访问&#xff0c;但是在集合中&#xff0c;元素没有与集合中的位置相关联。 Set是优化了搜索…