Android多线程

Android之多线程,包括线程、Java同步问题、阻塞队列、线程池、AsyncTask、HandlerThread、IntentService等内容。

本文是我一点点归纳总结的干货,但是难免有疏忽和遗漏,希望不吝赐教。
转载请注明链接:https://blog.csdn.net/feather_wch/article/details/79132183

有帮助的话请点个赞!万分感谢!

Android多线程(88题)

版本号: 2018/9/18(10:10)


问题汇总


线程(13)

1、什么是进程

  1. 系统分配资源的最小单位
  2. 进程就是程序运行的实体

2、什么是线程

  1. 系统调度的最小单位
  2. 一个进程中可以包含多个线程
  3. 线程拥有各自的计数器、堆栈和局部变量等属性,能够访问共享的内存变量

3、线程的好处

  1. 比进程的资源消耗要小,效率要更高
  2. 多线程的并发性能减少程序的响应时间
  3. 多线程能简化程序的结构,使程序便于理解和维护

4、线程的状态有哪些?

状态 解释 备注
New 新创建状态 线程已被创建,还未调用start,做一些准备工作
Runnable 可运行状态 start之后进入,Runnable线程可能在运行也可能没有在运行,取决于系统分配的时间
Blocked 阻塞状态 线程被锁阻塞,暂时不活动
Waiting 等待状态 线程不运行任何代码,消耗最少的资源,直至调度器激活该线程
Timed Waiting 超时等待状态 Waiting不同在于,可以在指定时间内返回
Terminated 终止状态 当前线程执行完毕:可能是run运行结束,或者出现未能捕获的异常导致线程终止

5、线程如何从新建状态进入可运行状态

Thread.start()

6、线程如何从可运行状态阻塞状态

  1. 线程在请求锁的时候会进入阻塞状态
  2. 线程一旦得到锁会返回到可运行状态

备注:

如下题目中的Object.wait()是指具体对象调用wait等方法---someObject.wait()Thread.join是指具体线程调用该方法—childThread.join()


7、线程如何从可运行状态切换到等待状态

  1. 进入等待:Object.wait()---当前线程进入等待状态(当前线程需要已经获得过锁,且调用后会失去锁)、Thread.join()---父线程会等待子线程
  2. 退出:Object.notify()和Object.notifyAll()

8、线程如何从可运行状态切换到超时等待状态

  1. 进入:Thread.sleep(long)、Thread.join(long)---让父线程等待子线程,子线程结束后父线程才继续执行、Object.wait(long)
  2. 退出:Object.notify()、Object.notifyAll()或者超时退出

9、线程如何从可运行状态切换到终止状态

  1. 执行完毕
  2. 异常退出

10、Object.notify()、Object.notifyAll()之间的区别

Object.notify(): 随机唤醒一个wait线程,调用该方法后只有一个线程会由等待池进入锁池
Object.notifyAll(): 会将对象等待池中的所有线程都进入锁池,进行竞争。竞争到的线程会继续执行,在释放掉对象锁后,锁池中的线程会继续开始竞争。(进入到锁池的线程,不会再进入等待池)

11、等待池和锁池是什么?

  1. 等待池:线程调用对象的wait方法后,会释放该对象的锁,然后进入到该对象的等待池中
  2. 锁池:线程想要获得对象的锁,但是此时锁已经被其他线程拥有,这些线程就会进入到该对象的锁池中。

12、创建线程的三种方法

  1. 继承Thread,重写run方法
  2. 实现Runnable接口,并实现该接口的run方法
  3. 实现Callable接口(Executor框架中的内容,优势是能在任务结束后提供一个返回值,Runnable无法这样做),重写call方法。
  4. 推荐第二种Runnable接口的方法,因为继承Thread没有必要。

13、终止线程的两种方法

  1. 调用Thread.interrupted()设置中断标志位,并通过Thread.currentThread().isInterrupted()检查标志位。缺点:被中断的线程不一定会终止
  2. run()方法中设置boolean标志位(需要volatile修饰为易变变量):条件满足时跳出循环,run运行结束,thread安全终止

14、实现Callable接口创建多线程

1-实现Callable接口,重写run方法。
2-使用FutureTask进行包装,并且执行

// 1、实现Callable接口,并用futureTask包装。
        FutureTask<Integer> futureTask = new FutureTask<>(new Callable<Integer>() {
    
            @Override
            public Integer call() throws Exception {
    
                // TODO sth,并返回结果。
                Integer result = 1;
                return result;
            }
        });
// 2、开启线程并且执行任务
        Thread thread = new Thread(futureTask);
        thread.start();

// 3、获取到线程执行的返回值
        Integer result = futureTask.get();

同步(8)

1、重入锁是什么?(3)

  1. 重入锁ReentrantLock在Java SE 5.0引入
  2. 该锁支持一个线程对资源的重复加锁
  3. 一个线程在锁住锁对象后,其他任何线程都无法进入Lock语句
  val mLock = ReentrantLock()
  mLock.lock()
  try {
    
      //需要同步的操作
  }finally {
    
      mLock.unlock() //finally中进行解锁,避免死锁问题
  }

2、可重入锁的用途?

  1. 阻塞队列就是使用ReentrantLock实现的。

3、条件对象/条件变量的作用(4)

  1. 用于管理那些获得锁却因部分条件不满足而无法正常工作的线程
  2. 可以通过newCondition获得锁lock的条件变量(和ReentrantLock配合使用
  3. 条件对象调用await方法,当前线程就会阻塞并且放弃该锁
  4. await线程会进入阻塞状态,直到另一个线程,调用同一条件对象的signalAll()方法,之后等待的所有线程通过竞争条件去抢锁
        //1. 可重入锁
            val mLock = ReentrantLock()
            mLock.lock()
        //2. 条件变量
            val condition = mLock.newCondition()
            try {
    
                while(条件不满足){
    
        //3. await进入Block状态
                    condition.await()
                }
        //4. 条件满足方会进行后续操作
                        //...
        //5. 操作完成后调用同一条件变量的signalAll去激活等待该条件的线程
                condition.signalAll()
            }finally {
    
                mLock.unlock() //finally中进行解锁,避免死锁问题
            }

4、synchronized同步方法(4)

  1. Lockcondition提供了高度的锁定控制,然而大多数情况下不需要这样麻烦
  2. 从Java 1.0开始,每个对象都有一个内部锁
  3. 当一个方法使用synchronized修饰,意味着线程必须获得内部锁,才能调用该方法
synchronized public void doSth() throws InterruptedException{
    
    //1. 条件不满足,进入Block状态
    while(条件不满足){
    
        wait();
    }
    //2. 条件满足方会进行后续操作
        //...
    //3. 解除该锁,并通知所有阻塞的线程
    notifyAll();
}
  1. 备注:Kotlin学的不深,暂时没找到Kotlin中同步的方法,就用Java实现

5、同步代码块的使用(1)和问题(2)

  1. java中可以通过给一个Object对象上锁,来使用代码块
  2. 同步代码块非常脆弱不推荐
  3. 一般实现同步,最好使用java.util.concurrent包下提供的类,例如阻塞队列
Object object = new Object();
synchronized (object){
    
    //进行处理, 不推荐使用
}

6、synchronized方法和synchronized同步代码块的区别?

  1. 用synchronized修饰符修饰的方法就是同步方法
  2. synchronized代码块需要一个对象锁

7、死锁是什么?

死锁是指两个或者两个以上线程/进程进行资源竞争时出现了阻塞现象,如果没有外力帮助,它们都将无法继续工作下去,此时系统处于死锁状态

8、可能出现死锁的场景

  1. 可重入锁ReentrantLockmLock.lock()后如果出现异常,但是没有在try-catchfinally中没有执行mLock.unLock()就会导致死锁。
  2. notifynotifyAll更容易出现死锁

Java中的volatile(13)

1、Java的堆内存是什么?(2)

  1. 堆内存用于存储对象实例
  2. 堆内存被所有线程所共享: 会存在内存可见性问题

2、 Java中的局部变量、方法定义的参数是否会被线程所共享?

  1. 局部变量、方法定义的参数则不会在线程间共享:不存在内存可见性问题,也不会受到内存模型影响,

3、Java内存模型的作用

  1. Java内存模型控制线程之间的通信,决定了一个线程对共享内存的写入何时对另一个线程可见。
  2. 定义了线程和主存之间的抽象关系:
    1. 线程之间的共享变量存储在主存中,每个线程都有一个私有的本地内存,本地内存中存储了该该线程贡献变量的副本,
    2. 本地内存是Java内存模型中的抽象概念,实际上并不存在,覆盖了缓存、写缓存区、寄存器等区域。

4、Java内存模型图

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猎羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值