最详细的多线程讲解!

本文详细介绍了Java中的多线程概念,包括线程与进程、并发与并行的区别,以及创建线程的两种方式。文章讨论了线程的生命周期、常用方法如interrupt()、wait()、notify()、join()等,并探讨了线程异常处理的策略,包括全局异常处理器的使用。
摘要由CSDN通过智能技术生成

线程、进程、并发、并行

1、线程与进程

  • 线程也被称作轻量级进程,线程是进程的执行单元;
  • 线程是进程的组成部分,一个进程可以拥有多个线程,一个线程必须有一个父进程;

2、并发与并行

  • 并发:指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果;
  • 并行:指在同一时刻,有多条指令在多个处理器上同时执行;

在这里插入图片描述

创建线程的两种方式

1、继承Thread类创建线程类

通过继承Thread类来创建并启动多线程的步骤如下:

  1. 定义Thread类的子类,并重写该类的run()方法。把run()方法称为线程执行体;
  2. 创建Thread子类的实例,即创建线程对象;
  3. 调用线程对象的start()方法来启动该线程;
public class Test7 extends Thread{
    @Override
    public void run() {
        //当线程类继承Thread类时,可以直接调用getName()方法来返回当前线程的名。
        System.out.println(getName());
    }

    public static void main(String[] args) {
        //调用Thread的currentThread方法获取当前线程
        System.out.println(Thread.currentThread().getName());
        new Thread(new Test7()).start();
    }
}
//控制台打印
main
Thread-0
复制代码

在这里插入图片描述2、实现Runnable接口创建线程类

通过实现Runnable接口来创建并启动多线程的步骤如下:

  1. 定义Runnable接口的实现类,并重写该接口的run()方法;
  2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象;
  3. 调用线程对象的start()方法来启动线程;
public class Test7 implements Runnable
{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        //调用Thread的currentThread方法获取当前线程
        System.out.println(Thread.currentThread().getName());
        new Thread(new Test7()).start();
        
        //设定线程名字
        //new Thread(new Test7(),"新线程").start();
    }
}
//控制台打印
main
Thread-0
复制代码

3、创建线程的两种方式对比

采用实现Runnable接口的方式:

  • 还可以继承其他类;
  • 这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况;
  • 如需访问当前线程,则必须使用Thread.currentThread()方法;

采用继承Thread类的方式:

  • 已经继承了Thread类,所以不能再继承别的类;
  • 如需访问当前线程,直接使用this即可获得当前线程;

推荐使用接口的形式;

4、对同一线程多次调用start()方法会怎样?

public class Test implements Runnable {

    @Override
    public void run() {
        System.out.println("Test");
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new Test());
        thread.start();
        thread.start();
    }
}
复制代码

运行控制台会报错: 在这里插入图片描述 这是因为start()方法会在调用开始前检查当前线程的状态。线程创建时默认状态为0,当调用start()方法后,线程状态被修改,所以再次调用start()方法会报错;

    /* Java thread status for tools,
     * initialized to indicate thread 'not yet started'
     */
    private volatile int threadStatus = 0;
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
复制代码

5、容易混淆的创建线程的几种方式? 在这里插入图片描述 网上对于创建线程的几种方式各有不同,有说两种、四种、三种的?那么到底是几种呢?

    /* What will be run. */
    private Runnable target;

    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
复制代码

我们查看Thread源代码可知,其实本质上就两种,一种是继承Thread,重写run方法的话,那么Thread原本的run方法则不再存在,我们调用的就是我们重写后的方法。

还有一种就是实现Runnable并重写run方法,此种方式的话,我们传入了Runnable对象,如上代码进行判断,target不为空,则执行了target的run方法;

查看网上其它的创建方式,其实本质上都是调用的我们最基本的两种创建方式,只是对他们进行了封装!

6、如果同时使用两种创建方式运行多线程会出现什么结果?

public class Test{
    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;

这是为什么呢?这是因为我们重写了Thread的run()方法,所以即使我们传入了Runnable对象,但是下面的代码已经不存在了。最终是直接执行我们所重写的run()方法

    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
复制代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值