当前位置: 首页>后端>正文

【Android】多线程知识汇总

汇总知识

《Java并发编程之美》学习笔记 - 简书

并发编程- java.util.concurrent用户指南 - 简书

Java高并发必学--concurrent包-腾讯云开发者社区-腾讯云

并发编程基础 - 安全性、活跃性、性能问题_竞态条件和活跃性问题 性能问题-CSDN博客

线程

进程和线程概览

Java 多线程编程 | 菜鸟教程

并发系列(1)之 Thread 详解 - 三枣 - 博客园

Thread类讲解_thread类详解-CSDN博客

多线程系列(二) -Thread类使用详解

线程状态

  • 新建(New):新建后未启动的线程;
  • 运行(Runnable):包括运行中(Running)和就绪(Ready)两种状态;也就是正在运行,或者等待 CPU 分配执行时间;
  • 等待(Waiting):无限期的等待其他线程显示唤醒;
  • 超时等待(Timed_Waiting):一定时间内没有被其他线程唤醒,则由系统自动唤醒;
  • 阻塞(Blocked):等待获取排它锁;
  • 终止(Terminated):运行终止;

线程间的通讯

其实所有的多线程问题,其本质都是线程之间的通讯问题,也有的说是通讯和同步两个问题(线程间操作的顺序);但我觉得同步仍然是线程之间通过某种方式进行通讯,确定各自执行的相对顺序;所以仍然可以算作是一种通讯问题;这里线程之间的通讯问题可以分成两种:

  • 共享变量,类似锁对象、volatile、中断等操作都可以算是共享变量通讯;
  • 消息传递,类似 wait\notify、管道等则可以算是通过消息直接传递通讯;

中断线程

线程停止的三种方式超详细-CSDN博客

中断线程一般会设置标志位,而设置标志位分两种方式:

  1. 直接自己定义一个标志位,作为线程是否结束的标记

  2. 使用标准库里自带的一个标志位;

    使用 Thread.currentThread().isInterrupted() 作为标志位

    public class Demo3 {
       public static void main(String[] args) {
           Thread t = new Thread(()->{
              while(!Thread.currentThread().isInterrupted()){
                  System.out.println("hello Thread");
              }
               System.out.println("t 执行完");
           });
    
           t.start();
    
           try {
               Thread.sleep(300);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
    
           t.interrupt();
           System.out.println("设置让 t 线程结束");
       }
    }
    

注意:interrupt 方法的行为,有两种情况

① 当 t 线程在运行状态时,会设置标志位(Thread.currentThread().isInterrupted())为 true;

② 当 t 线程在阻塞状态时(sleep),就不会设置标志位,而是触发一个 InterruptedException,这个异常会把 sleep 提前唤醒。

java线程取消与关闭的多种方法_future 关闭线程-CSDN博客

关闭线程的正确方法:“优雅”的中断 - 简书

线程中的异常捕获

Thread对象通过setUncaughtExceptionHandler方法来设置UncaughtExceptionHandler;

Future

重学多线程之一:Future

多线程基础之设计模式Future模式_线程 future-CSDN博客

Future 模式: 买蛋糕时,与其一直等待结果, 不如先拿一张 "提货单", 获取提货单并不耗费时间, 这里的 "提货单" 我们就称为 Future 角色

多线程基础之设计模式Thread-Per-Message模式_thread per message-CSDN博客

Future与FutureTask接口实现示例详解java脚本之家

Java之Future(cancel,iSDone)_future.isdone-CSDN博客

CompletableFuture

异步编程利器:CompletableFuture详解

Java8新特性:CompletableFuture 方法介绍_java supplyasync whencomplete-CSDN博客

HandlerThread

Android多线程:HandlerThread的原理及使用 - 简书

守护线程

Java基础(二十)——守护线程(setDaemon)、合并线程(join)、读写分离集合(CopyOnWriteArrayList)、生产者消费者模式-CSDN博客

线程池

JAVA阻塞队列和线程池原理_java线程池为什么使用阻塞队列作为任务队列-CSDN博客

Android开发-通过ExecutorService构建一个APP使用的全局线程池_android 定义全局线程池类-CSDN博客

线程池的任务执行顺序:核心线程(corePoolSize),线程队列workQueue,非核心线程(maximumPoolSize),都满了则执行线程提交拒绝策略(handler)。

Java线程池七个参数详解_线程池七大核心参数-CSDN博客

终止线程池

关闭线程的正确方法:“优雅”的中断 - 简书

线程池的shutdown()与shutdownNow()方法的区别-CSDN博客

Java线程池,isShutDown、isTerminated的作用与区别 - 疯子110 - 博客园

定时执行者服务 ScheduledExecutorService

ScheduledExecutorService详解-CSDN博客

scheduleAtFixedRate (Runnable, long initialDelay, long period, TimeUnit timeunit)

如果一个任务占用了比计划的时间间隔更长的时候,下一次执行将在当前执行结束执行才开始。计划任务在同一时间不会有多个线程同时执行。

scheduleWithFixedDelay (Runnable, long initialDelay, long period, TimeUnit timeunit)

除了 period 有不同的解释之外这个方法和 scheduleAtFixedRate() 非常像。

scheduleAtFixedRate() 方法中,period 被解释为前一个执行的开始和下一个执行的开始之间的间隔时间。而在本方法中,period 则被解释为前一个执行的结束和下一个执行的结束之间的间隔。因此这个延迟是执行结束之间的间隔,而不是执行开始之间的间隔。

AsyncTask

Android学习笔记:多个AsyncTask实例的并发问题 - 51kata - 博客园

ANDROID的AsyncTask为何弃用 asynctask缺点

线程池的封装

线程池 - 简书

原子性Atomic包

线程安全性详解(原子性、可见性、有序性)-原子性可见性有序性

并发编程-04线程安全性之原子性Atomic包的4种类型详解_atomiclong线程安全-CSDN博客

线程安全之AtomicBoolean_线程安全的boolean-CSDN博客

原子操作类AtomicInteger详解-CSDN博客

多线程(七)原子操作、阻塞队列_atomicboolean 默认值-CSDN博客

set()方法注意

.set()方法:设置指定值,无锁,多线程使用会出问题,一般用于初始化数值

    AtomicInteger
    /**
     * Sets to the given value.
     *
     * @param newValue the new value
     */
    public final void set(int newValue) {
        value = newValue;
    }

lazySet()方法与set()方法区别

lazySet()方法没有缓存刷新。

换句话说,我们的变化最终只对其他线程可见。这意味着从不同的线程对更新的 AtomicReference 调用 get()可能会给我们带来旧的值。

高并发的问题

AtomicLong,CAS的过程中,当A线程在C(compare)和S(swap)之间有其他线程插入S,则,A线程的S始终执行不了,一直在循环,待A线程的A和S之间没有其他线程插入S时,才能S成功。但实际按执行顺序A线程不是在最后,导致最终会S错误的值。

如果对结果和执行顺序有严格要求,可以用锁。

Happens-Before原则(先行发生原则)

Happens-Before原则(先行发生原则) - 简书

Condition类,等待

java中Condition类的详细介绍(详解) - 郭慕荣 - 博客园

LongAdder(累加器,java8新加入)

LongAdder详解 - 简书

Java LongAdder类介绍、代码示例、底层实现原理及与分段锁的区别-CSDN博客

原理

适用于高并发对单一变量增减后,进行求和取值。

当多个线程同时进行加法操作时,每个线程都会被分配到一个独立的"cell",从而减少了竞争条件。

当需要获取最终的加法结果时,LongAdder会将"base"和所有"cell"中的值进行求和,得到最终的结果。

对比AtomicLong

在高度并发竞争情形下,AtomicLong每次进行add都需要flush和refresh(这一块涉及到java内存模型中的工作内存和主内存的,所有变量操作只能在工作内存中进行,然后写回主内存,其它线程再次读取新值),每次add()都需要同步,在高并发时会有比较多冲突,比较耗时导致效率低;

而LongAdder中每个线程会维护自己的一个计数器,在最后执行LongAdder.sum()方法时候才需要同步,把所有计数器全部加起来,不需要flush和refresh操作; AtomicLong耗时间;LongAdder耗内存;

AtomicLong,高并发结果可能会出错,详见上方<原子性Atomic包>之<高并发的问题>。

Java中的锁

Java中的锁详解篇_java 锁-CSDN博客

Java中的锁(synchronized、Lock、ReadWriteLock)及常用线程安全类原理(CopyOnWriteArrayList、ConcurrentHashMap)_java四种锁机制-CSDN博客

乐观锁的机制CAS:Compare-And-Swap比较并交换

线程学习(25)-乐观锁方式CAS简介_cas方式-CSDN博客

CAS:线程始终在高速运行,没有停歇;

synchronized:会让线程在没有获得锁的时候,发生上下文切换,进入阻塞;

CAS效率高的原因:线程就好像高速跑道上的赛车,高速运行时,速度超快,一旦发生上下文切换,就好比赛车要减速、熄火,等被唤醒又得重新打火、启动、加速... 恢复到高速运行,代价比较大;

AtomicInteger类主要利用CAS + volatile和native方法来保证原子操作,从而避免synchronized的高开销,提升执行效率。

CAS实际应用的场景应该是,线程数量较少,多核CPU的情况,这种情况下,使用CAS可以提升效率。

ABA问题

ABA问题-CSDN博客

synchronized

全网最硬核的 synchronized 面试题深度解析_synchronized面试题-CSDN博客

synchronized - 简书

Synchronized相比ReentrantLock,在使用偏向锁时甚至都不需要自旋。因此在锁细粒度很小的情况下,Synchronized不太会升级为重量级锁,此时性能上会比ReentrantLock更加优秀。

进阶

ForkJoinPool

ForkJoinPool 分支/合并框架_forkjoinpool.managedblocker-CSDN博客

线程池ForkJoinPool简介 - Java老K - 博客园

ForkJoinPool的使用及基本原理_51CTO博客_forkjoinpool使用场景

Handler机制

闲聊Android中的Handler机制

全面详解Android实现多线程的几种方式(史上最全,最详细)_android多线程实现方式-CSDN博客

子线程中使用Handler

Android如何在子线程中使用Handler_handler运行在子线程如何写-CSDN博客

Handler的使用_子线程中使用handler的场景-CSDN博客

其他问题

单例Bean一定不安全吗?

面试官:单例Bean一定不安全吗?实际工作中如何处理此问题?-51CTO.COM


https://www.xamrdz.com/backend/3t71940635.html

相关文章: