Android线程

Android线程需要学习什么东西?

先说答案:
什么是主线程,和怎么避免在主线程中执行耗时操作

1. 主线程(UI线程)理解主线程是如何工作的,以及为什么不应该在主线程中执行耗时操作,从而避免应用界面失去响应(ANR:Application Not Responding)。

    事件循环:主线程运行着一个事件循环,通常称为消息循环(Message Loop)或事件分发循环(Event Dispatch Loop)。它负责从事件队列中逐个取出事件并处理它们。这些事件可以是用户的交互动作,也可以是系统的绘制请求等。
    UI更新:所有的UI更新都必须在主线程中进行,因为Android的UI工具包不是线程安全的。如果尝试从非UI线程更新UI,程序会抛出异常。
    响应性:要保持应用的响应性,主线程必须能够快速地处理事件。如果主线程被耗时的任务阻塞,它将无法及时处理其他事件,包括UI更新,导致界面卡顿或者触摸无响应。
    ANR的产生:如果主线程在特定时间内(如5秒内)无法响应用户输入事件或者广播接收器(BroadcastReceiver),系统将会弹出“应用程序未响应”(ANR)的对话框。发生这种情况时,用户可以选择等待或者强制关闭应用。

为什么不应该在主线程中执行耗时操作:

阻塞UI渲染:所有的UI渲染动作都是在主线程中完成的,如果主线程被耗时操作阻塞,UI渲染就会停滞,界面就无法更新,用户体验大打折扣。
引发ANR:如上所述,如果主线程被长时间占用,无法处理输入事件或者其他关键操作,系统最终会显示ANR对话框。
违反设计原则:Android的设计原则之一是保持应用的响应性,因此所有的耗时操作都应该在后台线程中进行。

2.怎么避免在主线程中执行耗时操作:

使用Handler和Looper:
通过在后台线程中处理耗时逻辑,然后使用Handler将结果回传到主线程进行UI更新。
消息(Message):Handler可以发送和处理包含数据的Message对象。
可运行对象(Runnable):Handler也可以排队执行Runnable对象,即代码块。
消息队列(Message Queue):Handler关联的Looper拥有一个消息队列,它负责保持所有的消息(Message)和可运行对象(Runnable),直到它们被分发。
Looper: 每个Handler都需要绑定到一个线程的Looper。Looper是一个用于循环提取和分发消息队列中的消息的类。在Android中,主线程默认会有一个Looper。

主线程(UI线程)有一个默认的Looper,负责循环的从message queue中取出message或者runnable对象,取到handle中由handle处理,message/runnable是由handle发送的
handle和线程绑定 每个线程只有一个looper  UI不用创建 其他线程需要创建和开启循环 
handle可以sendmessage 或者post runnable
然后message或者runnable会加入messagequeue中 然后由looper由加入顺序一个一个提取到handle
// 创建一个子线程

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        // 执行耗时操作
        // 创建一个消息
        Message message = Message.obtain();
        message.what = 1; // 给消息设置一个整型值标识
        message.obj = "任务完成"; // 可以放置任何需要传递的数据
        // 发送消息到主线程的Handler
        mainHandler.sendMessage(message);
    }
});

// 主线程的Handler
Handler mainHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(@NonNull Message msg) {
        if (msg.what == 1) {
            // 在这里可以安全地更新UI
            String result = (String) msg.obj;
            textView.setText(result);
        }
    }
};

// 启动子线程
thread.start();


使用AsyncTask:
尽管已经被弃用,但AsyncTask仍是理解异步编程的一个好例子,它允许你在后台线程中执行操作,然后在主线程中更新UI。
使用Service:
对于不需要与用户互动的长时间运行的操作,可以使用服务(Service)。
使用IntentService(已弃用):
对于需要顺序执行的任务,可以使用IntentService,它会创建一个工作线程,并且所有任务都在该线程中逐个执行。
使用线程池:
通过ThreadPoolExecutor和Executors类创建线程池,管理后台任务的执行。

线程复用:线程池通过复用已经创建的线程来执行任务,避免了频繁创建和销毁线程的开销。
任务队列:线程池通常使用一个阻塞队列来存放待执行的任务。当所有的线程都忙于处理任务时,新提交的任务会被放入队列中等待,直到有线程变为可用。
动态线程管理:对于某些类型的线程池(如缓存线程池),线程池可以根据需要动态地调整线程的数量,增加新线程或者减少空闲线程。
核心线程和最大线程:线程池通常有两个关键参数:核心线程数和最大线程数。核心线程数是线程池希望保持活跃的线程数量,最大线程数是线程池允许创建的最大线程数量。
线程保活时间:对于超出核心线程数的线程,线程池会设置一个空闲保活时间。如果线程在这段时间内没有执行任务,则可能会被线程池回收。
任务调度和执行顺序:线程池不保证任务的执行顺序,除非是使用了特定类型的队列(如LinkedBlockingQueue)或者特定的线程池(如newSingleThreadExecutor)。一般情况下,任务的执行顺序取决于其在队列中的排列顺序以及线程池的调度策略。
线程池状态控制:线程池提供了方法来控制其状态,例如启动、关闭和终止。


使用协程(Kotlin):
如果你使用Kotlin编程,协程提供了一种更加强大和简洁的方式来处理异步任务和并发。
使用LiveData和ViewModel:
这些架构组件可帮助你以生命周期感知的方式管理UI相关数据和任务。
使用WorkManager:
对于需要确保执行,即使应用退出或设备重启也要完成的任务,可以使用WorkManager来安排这些任务。



在并发编程中,线程池是一种基于池化技术的线程使用模式,目的是减少在创建和销毁线程上的开销。Java提供了多种类型的线程池,主要通过`java.util.concurrent.ExecutorService`接口和它的实现类进行管理,主要类型包括:

1. **CachedThreadPool**

  - 缓存线程池可以创建一个可根据需要创建新线程的线程池,但会在之前构造的线程可用时重用这些线程。

  - 如果线程池当前没有可用的线程,缓存线程池就会创建新的线程。

  - 如果线程池中的线程在60秒内没有被使用,那么它们可能会被终止并从缓存中移除。

2. **FixedThreadPool**

  - 固定大小线程池可以重新使用固定数量的线程操作。

  - 固定线程池的核心和最大线程数是相同的。

  - 固定线程池使用的是无界队列来存放待执行的任务。

3. **SingleThreadExecutor**

  - 单线程化的线程池有且只有一个工作线程执行任务,所有任务保证按照任务队列的顺序(FIFO, LIFO, 优先级)执行。

4. **ScheduledThreadPool**

  - 调度线程池可以延迟或定时地执行任务。

  - 调度线程池的核心线程数是固定的,而非核心线程数(如果需要)可以是无限的。

  - 任务可以周期性重复执行。

5. **WorkStealingPool**

  - 这是Java 8引入的基于Fork/Join框架,它使用了工作窃取算法来提高线程间的工作效率。

  - 线程会尝试查找和执行其他线程创建的未执行的子任务。

6. **SingleThreadScheduledExecutor**

  - 这是ScheduledThreadPool的特例,它保证所有定时任务都在同一个线程中执行。

每种类型的线程池都有它自己的优势和用途。例如,CachedThreadPool适用于有大量短暂异步任务的场景,FixedThreadPool适用于负载比较重的服务器,而SingleThreadExecutor则适用于需要保证任务顺序执行的场景。

使用线程池的时候,重要的是要根据具体的应用场景选择最适合的线程池类型,并合理配置线程池的参数,以此来达到最优的性能表现。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容