Java实现多线程的三板斧

本文介绍了Java中实现多线程的三种方式:继承Thread类、实现Runnable接口和实现Callable接口。详细讲解了每种方式的具体步骤及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  Java一大特色就是支持多线程编程。
  可以使用三种方式实现多线程,分别是:

  • 继承Thread类
  • 实现Runnable接口
  • 实现Callable接口

1. 继承 Thread 类

  java.lang.Thread 是一个线程操作的核心类。

1.1 创建线程

  新建一个线程最简单的方法就是直接继承 Thread类,然后再覆写该类中的 run()方法,run方法 相当于主方法的 main,线程中的所有操作均在 run() 方法中实现。

class MyThread extends Thread {
    @Override
    // 覆写 run 方法,并在其内添加该线程所要执行的业务代码
    public void run() {
        System.out.println("创建线程");
    }
}

1.2 启动进程

  直接在主方法中调用覆写的 run 方法是不能启动线程的,其效果相当于把 run 当作普通方法进行调用。
  正确启动多线程的方法:
     调用 public symchronized void start() 方法。即调用 Therad类 的 start 方法。
  创建线程有三种方法,可是启动线程只能使用 start 方法。

public class Test {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        // 使用 Thread类 的 start方法 启动线程
        myThread.start();
    }
}

1.3 start 方法启动线程具体流程

  启动线程流程:

  •   start方法 调用 start0() 方法,这个方法是一个只声明而未实现的方法,同时使用了 native 进行了修饰
private native void start0();
  •   该方法调用了本地方法(native ,调用本地方法,C语言实现本地方法,一般为底层方法),Thread类 中有一个 registrNative 本地方法,该方法主要作用是注册一些本地方法供 Thread类 使用,如 start0(),stop0() 等,可以说,所有操作本地线程的本地方法都由它注册。
      这个方法存放在一个 static块 中,当该类被加载到 JVM 中时,他就会被调用,注册相应的本地方法
      所以 start0 实际调用的是本地方法 registrNative
  •   registrNative方法 又调用了其中的 JVM_StartThread方法
  •   而该方法又调用了 run方法
    所以,总的流程是 start -> start0 -> registrNative -> JVM_StartThread -> run
    start 方法流程图

1.4 不能重复启动线程

  当重复启动同一个线程时 ,start 会抛出一个 IllegalThreadStateException 异常 。 ![IllegalThreadStateException](https://img-blog.youkuaiyun.com/20180427095828661?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDczOTgzMw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)   因为 java.lang.Thread.start()方法一开始有一个状态检测,如果检测到当前线程已经启动,就会抛出这个异常。 ![start方法](https://img-blog.youkuaiyun.com/20180427100323941?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDczOTgzMw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

2. 实现 Runnable 接口

如果一个类为了实现多线程直接去继承 Thread类 就会有单继承局限,因为子类继承了 Thread类 就不能再继承其他的父类了。

2.1 创建线程

  通过 实现 Runnable接口 来创建新的进程。
class MyThread implements Runnable {
    @Override
    // 覆写 run 方法,并在其内添加该线程所要执行的业务代码
    public void run() {
        System.out.println("创建线程");
    }
}

2.2 启动线程

  Thread类 中有一个重载构造方法,可以接受一个 Runnable 对象。
public Thread(Runnable target);
  所以我们可以通过这个构造来启动线程。
public class Test {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread);
        thread.start();
    }
}
  也可以给 Thread类 构造传入 Runnable接口 的匿名内部类或 Lambda表达式 来启动线程。
public class Test {
    public static void main(String[] args) {
        // Runnable接口的匿名内部类
        Thread thread = new Thread(new Runnable() { 
            @Override
            public void run() {
                System.out.println("创建线程");
            }
        });
        thread.start();
        // Lambda表达式
        Runnable runnable = () -> System.out.println("创建线程");
        Thread thread2 = new Thread(runnable);
        thread2.start();
    }
}

2.3 继承 Therad类 和实现 Runnable接口 创建线程的区别

  • 从使用形式上来说, Runnable 实现要比 Thread 好,因为 Runnable 可以避免单继承限制,一个子类可以实现多个接口。
  • 另外,Thread 是一个实现 Runnable接口 的子类,并且 Thread 覆写了 Runnable接口的run方法。
    Thread类定义
     所以 实现Runnable接口 创建线程的方式其实上一个代理设计模式。
      实现子类为 真正业务类。
      Thread类 为代理类。
     两个类都实现 Runnable接口,组成代理设计模式。
    Runnable接口的继承结构
  • 实现 Runnable接口 创建线程的方式可以更好的描述线程之间的程序概念(Thread 不好描述)

3. 实现 Callable接口

  从 JDK1.5 追加了新的开发包:java.uti.concurrent,这个包只要用来进行高并发编程使用,在这个包中有一个新的接口 Callable。

public interface Callable<V> {
    V call() throws Exception;
}

  Callable接口 是一个泛型接口,它的 run方法 有一个返回值。

3.1 创建线程

  覆写 Callable接口 的 call方法,记得要传入具体类型参数。

class MyThread implements Callable<Boolean> {
    @Override
    public Boolean call() throws Exception {
        System.out.println("创建线程");
        return true;
    }
}

3.2 启动线程

  将 Callable接口 接口的子类的实例化传入 FutureTask 的构造方法,来创建 FutureTask 的一个对象。

FutureTask task = new FutureTask<>(new MyThread());

  将 FutureTask 的对象传入 Thread 构造,然后使用 start 启动线程。

new Thread(task).start();

public class Test12 {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        FutureTask<Boolean> task = new FutureTask(new MyThread());
        new Thread(task).start();
        // get 方法或抛出异常
        System.out.println(task.get());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值