Tao
Tao

java创建线程的方式

本文基于JDK11版本探讨下,JAVA创建线程的方式有哪些?我这边先给我的答案,只有两种方式继承THREAD类、实现RUNNABLE接口,ORACLE官方文档也说只有两种方式。

Thread类是Java提供的表示线程的类。它是一个具体的类,实现了Runnable接口,并提供了额外的线程控制和管理功能。通过继承Thread类,可以创建自定义线程类。

Runnable接口是Java定义的一个函数式接口,用于表示可运行的任务。通过实现Runnable接口,可以将任务逻辑封装在run()方法中,并将其传递给Thread对象来创建线程。

Thread本身是实现了Runnable接口的类,而Runnable只是一个接口。当你创建并启动一个Thread时,它将开启一个新的线程并在这个新线程中执行其run()方法;而创建一个Runnable并将其传递给Thread的构造函数,当Thread启动时,它将在新的线程中执行Runnable的run()方法。

具体代码分析如下:Thread类本身实现Runable接口

java

public class Thread implements Runnable {
 ......省略代码
 //构造Thread实例传递的runable实例
    public Thread(Runnable target) {
            this(null, target, "Thread-" + nextThreadNum(), 0);
    }
    public Thread(ThreadGroup group, Runnable target, String name, long stackSize) {
            this(group, target, name, stackSize, null, true);
    }
    private Thread(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc,
                   boolean inheritThreadLocals) {
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }
      ......省略....
      //将runable 实例赋值给this.target字段
      this.target = target;
      .....省略......
    }
    @Override
    public void run() {
    // 代码关键点判断target是否为空
        if (target != null) {
            target.run();
        }
    }
}

如果同时实现Runnable的run方法、重写Thread的run方法会发生什么结果?

代码如下:

java

public class ThreadDemo {
    public static void main(String[] args) {
        new Thread(()->{
            System.out.println("Runnable run");
        }){
            @Override
            public void run() {
                System.out.println("Thread run");
            }
        }.start();
    }
}

输出结果

shell

Thread run

在Java中,Runnable和Thread都用于实现多线程编程,但是使用Runnable接口来创建线程通常被认为是更好的选择,有以下几个原因:

  • 避免继承限制:Java是单继承语言,如果使用Thread类创建线程,就无法再继承其他类。而使用Runnable接口,可以避免这个限制,因为Java允许类实现多个接口。

  • 提高代码的组织性:将任务逻辑与线程逻辑分离,使用实现Runnable接口的类作为任务,可以更好地将代码模块化和组织化。这样可以提高代码的可读性、可维护性和可测试性。

  • 适应性更强:Runnable接口使得任务代码可以在多个线程之间共享,可以更灵活地在不同线程之间切换任务。而使用Thread类创建的线程,任务代码与线程代码紧密耦合,不够灵活。

  • 资源共享和线程池的使用:使用Runnable接口可以更好地支持线程池的使用。线程池是一种重用线程的机制,可以有效地管理线程的生命周期和资源。通过将Runnable任务提交给线程池,可以更好地管理资源并提高系统性能。

  • 扩展性和可替换性:如果以后需要更换线程实现的方式,例如使用Executor框架或其他的并发工具,使用Runnable接口更容易进行迁移和替换。而使用Thread类创建的线程,在替换时可能需要修改大量的代码。

总的来说,使用Runnable接口来实现Java线程更好的原因是它提供了更好的代码组织性、可维护性和可扩展性,同时避免了继承限制,并且更适应于资源共享和线程池的使用。

在Java中,有多种方法可以实现线程。以下是一些常见的java创建线程实现方法:

  • 继承Thread类:这是最基本的线程实现方法之一。通过创建一个继承自Thread类的子类,重写run()方法来定义线程的执行逻辑。然后,可以创建该子类的实例并调用start()方法来启动线程。

  • 实现Runnable接口:另一种常见的线程实现方法是实现Runnable接口。定义一个类实现Runnable接口,并实现其run()方法。然后,可以创建该类的实例,并将其作为参数传递给Thread类的构造函数,然后调用Thread的start()方法来启动线程。

  • 使用Callable和Future:Java提供了Callable和Future接口,允许线程执行并返回一个结果。Callable接口类似于Runnable接口,但它的call()方法可以返回一个值。可以使用ExecutorService的submit()方法来提交Callable任务,并返回一个Future对象,以便获取任务的结果。

  • 使用线程池:线程池是一种维护和管理线程的机制。通过使用Java提供的Executor框架,可以创建线程池并将任务提交给线程池来执行。这种方式可以提高线程的效率和性能,并管理线程的生命周期。

  • 使用Java并发类:Java提供了一些并发类,如Semaphore、CountDownLatch、CyclicBarrier等,可以帮助在多个线程之间进行同步和协调操作。这些类提供了更高级的线程控制和同步机制。

  • 使用定时器:Java提供了Timer类和ScheduledExecutorService接口,可以用于定时执行任务或周期性执行任务。

但是原理来说只有两种方式,通过重写Thread#run方法和实现Runable类#run方法。深入到源码层面上看的话,都是通过Thread类run方法来实现的,其实两种方式本质上都是一样的。

通常创建线程我们可以分为两类。准确的讲,创建线程只有一种方式那就是构造Thread类,而实线程的执行单元有两种方式。

  1. 实现Runnable接口的run方法,Thread类run方法会调用Runnable实例的run方法

  2. 重写Thread的run方法(继承Thread类)

相关内容