欢迎光临
我们一直在努力

继承Thraed类VS实现Runnable接口

文章目录

  • 前言
  • 一、两种方式的代码实现
    • 1.方式一:继承Thread类
    • 2.方式二:实现Runnable接口
  • 二、核心区别深度解析
    • 1.继承限制:单继承VS多实现
    • 2.任务与线程的耦合度
    • 3.资源共享能力
    • 4.代码复用性
  • 三、实际开发中该怎么选?
    • 什么时候用继承Thread?
    • 什么时候用实现Runnable?
    • 现代Java的写法:Lambda表达式
  • 五、总结

前言

在Java多线程编程中,创建线程是入门的第一道坎,很多初学者都会遇到这样一个问题:到底是继承Thread类,还是实现Runnable接口? 这两种方式看起来都能实现多线程,但背后却有着本质的区别。选对了,代码灵活易维护;选错了,可能后续扩展处处受限。今天这篇文章,我们就来彻底讲透这两种方式的区别,帮你一次性搞清楚到底该怎么选。


一、两种方式的代码实现

1.方式一:继承Thread类

通过继承Thread类并重写run方法,可以定义线程的执行逻辑。Thread类本身已经实现了Runnable接口。

class MyThread extends Thread{
@Override
public void run(){
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"执行任务"+i);
}
}
}
publid class ThreadDemo{
public static void main(String[] args){
MyThread t1=new MyThread();
MyThread t2=new MyThread();
t1.start();
t2.start();
}
}

注意:一定要调用start()方法,而不是直接调用run(),直接调用run()不会创建新线程,只是一个普通的方法调用。

2.方式二:实现Runnable接口

定义一个类实现Runnable接口,重写run()方法,然后将该类的实例作为参数传给Thread的构造方法。

class MyRunnable implements Runable{
@Override
public void run(){
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"执行任务"+i);
}
}
}
public class RunnableDemo{
public static void main(String[] args){
MyRunnable myRunnable=new MyRunnable();
Thread t1=new Thread(myRunnable,"线程1");
Thread t2=new Thread(myRunnable,"线程2");
t1.start();
t2.start();
}
}


二、核心区别深度解析

1.继承限制:单继承VS多实现

这是两者最本质的区别。 Java是单继承语言,一旦你的类继承了Thread类,就无法再继承其他类了。如果你的业务类本来需要继承某个基类,用Thread的方式就会直接起冲突。 而实现Runnable接口则没有这个限制——Java支持一个类实现多个接口,实现了Runnable的同时还可以继承其他父类、实现其他接口。

//无法同时继承Thread类和其他类
class MyService extends BaseService,Thread{//编译错误!
//…
}

//可以同时继承BaseService并实现Runnable
class MyService extends BaseService implements Runnable{
//..
}

2.任务与线程的耦合度

继承Thread类的方式,线程对象和任务是绑在一起的——任务代码直接写在Thread的子类中,线程和任务无法分离。 而实现Runnable接口的方式,Runnable只负责定义任务逻辑,Thread负责执行,实现了任务与线程的分离,更符合单一职责原则。

3.资源共享能力

这是一个非常关键的区别。 继承Thread类时,每个线程都拥有独立的Thread实例,线程资源无法共享。 而实现Runnable接口时,多个线程可以共享一个Runnable实例,从而轻松实现资源共享。 来看一个经典的卖票例子: 继承Thread类(无法共享资源):

class TicketThread extends Thread{
private int tickets=10;
@Override
public void run(){
while(tickets>0){
System.out.println(getName()+"卖出一张票,剩余:"+ —tickets);
}
}
}
//创建三个线程,每个线程都有自己的10张票=总共卖了30张
TicketThread t1=new TicketThread();
TicketThread t2=new TicketThread();
TicketThread t3=new TicketThread();

实现Runnable接口(共享资源):

class TicketRunnable implements Runnable{
private int tickets=10;
@Override
public void run(){
while (tickets>0){
System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余:"+ —tickets);
}
}
}
//三个线程共享同一个Runnable实例=总共只卖10张票
TicketRunnable task=new TicketRunnable();
Thread t1=new Thread(task);
Thread t2=new Thread(task);
Thread t3=new Thread(task);

4.代码复用性

由于Runnable是一个接口,同一个Runnable实现可以被多个线程复用,提高了代码的复用性。而继承Thread创建的每个线程都是独立的,无法直接共享代码。

三、实际开发中该怎么选?

什么时候用继承Thread?

  • 非常简单的线程任务,不需要继承其他类
  • 需要直接操作Thread类的特有方法
  • 快速原型验证

什么时候用实现Runnable?

  • 绝大多数实际开发场景都推荐使用
  • 类需要继承其他父类时
  • 多个线程需要共享同一份资源或数据时
  • 希望将任务逻辑与线程管理分离,提高代码的可维护性时

现代Java的写法:Lambda表达式

从Java 8开始,因为Runnable是函数式接口(只有一个抽象方法run()),可以用Lambda表达式进一步简化代码:

new Thread(()->{
System.out.println("Lambda创建的线程正在运行");
}).start();

这在日常开发中非常常见,简洁又优雅。


五、总结

继承Thread类的方式简单直接,适合非常简单的场景。而实现Runnable接口的方式则更加灵活、可扩展,支持资源共享、任务解耦,并且不受单继承的限制。 一句话建议:在实际开发中,有限选择实现Runnable接口的方式,除非你有非常特殊的理由必须继承Thread。

希望这篇文章能帮你彻底搞懂这两种方式的区别。

赞(0)
未经允许不得转载:171主机测评 » 继承Thraed类VS实现Runnable接口
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址