初识多线程

内容纲要

实现多线程的方式

官方

  • 方法一: 实现Runnable类 (更好)
    • 从解构角度,创建线程和线程的具体逻辑应该分离实现解耦
    • 使用继承的方式,我们每次需要创建一个线程就需要一个独立的类独立的线程,独立的线程消耗会很大,Runnable可是使用线程池
  • 方法二:继承Thread类
  • 两种方法的本质对比
    • 方法一:最终调用target.run(),target也就是新创建实现Runnable的类
    • 方法二:run()整个都被重写

同时使用两种方法会怎么样?

public class BothRunnableThread {

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("我来自Runnable");
            }
        }) {
            @Override
            public void run() {
                System.out.println("我来自Thread");
            }
        }.start();
    }
}

最终会执行Thread中的方法,原因:实现Runnable后,在run方法中则会去调用Runnable对象的run方法,但是紧接着继承Thread类,再重写run方法,所以run方法中原本调用Runnable对象的run方法的语句就被覆盖了,Runnable的run得不到运行,所以执行的是Thread中的方法

最精准的描述

  • 通常我们可以分为两类, Oracle也是这么说的
  • 准确的讲,创建线程只有一-种方式那就是构造Thread类,而实现线程的执行单元有两种方式
    • 方法一:实现Runnable接口的run方法,并把Runnable实例传给Thread类
    • 方法二:重写Thread的run方法(继承Thread类)

启动线程的正确和错误方式

start()和run()的比较

  • run() run方法还是在主线程
  • start() 真正开启了一个子线程

start()方法含义

  • 启动新线程,通知jvm在空闲的时候运行新线程
  • 准备工作:让自己处于就绪状态(已经获取到除CPU以外的所有资源,比如设置了上下文,栈,线程状态,寄存器)
  • 不能重复调用start()

停止线程

如何停止线程?

  • 原理介绍:使用interrupt来通知,而不是强制

特殊方法

  • static boolean interrupted() 返回之后会将中断状态设置为false
  • boolean isInterrupted() 返回中断状态后不会清除状态
  • Thread.interrupted()的目标对象

响应中断的方法总结


Thread 与 Object

方法概览

wait、notify、notifyAll作用、用法

阻塞阶段

另-个线程调用这个对象的notify()方法且刚好被唤醒的是本线程;
另一个线程调用这个对象的notifyAll()方法;
过了wait(long timeout)规定的超时时间,如果传入0就是永久等待;
线程自身调用了interrupt()

  • notify、notifyAll 都需要在synchronized 关键字保护下运行,如果在外面则会抛出异常

join

在每个线程运行结束后,都会去调用notify_all进行wait的唤醒

even.join();
# join的等价代码
synchronized (even){
    even.wait();
}

yield 方法详解

释放自身的CPU时间片,状态依然是Runable状态,原因:yield释放的时间片并会释放自己的锁,不会陷入阻塞,下一次CPU调度随时都可能调度起来

线程个属性纵览

线程各属性总结

线程的未捕获异常UncaughtException应该如何处理?

为什么需要UncaughtExceptionHandler ?

  • 主线程可以轻松发现异常,子线程却不行
  • 子线程异常无法用传统方法捕获
  • 不能直接捕获的后果,提高健壮性

解决方案

  • 方案一(不推荐 ) :手动在每个run方法里进行try catch
  • 方案二(推荐) :利用UncaughtExceptionHandler
    • UncaughtExceptionHandler接口
    • void uncaughtException(Thread t, Throwable e);

异常处理器的调用策略

自己实现

  • 给程序统一设置

  • 给每个线程单独设置

  • 线程池设置

volatile 解决可见性

每次更新了之后,volatile都会强制将线程内存刷新回主内存中

THE END
分享
二维码
< <上一篇
下一篇>>