extend Thread 和 implements Runnable

本文探讨了Java中通过继承Thread类与实现Runnable接口两种方式创建线程的区别。前者每个实例只能启动一次,后者则可以在同一实例上创建多个线程。

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

原文地址:extend Thread implements Runnable 作者: test

一个Thread的实例只能产生一个线程

or:

同一实例(Runnable实例)的多个线程

look:


public class Test {
 public static void main(String[] args) throws Exception{
  MyThread mt = new MyThread();
  mt.start();
  mt.join();
  Thread.sleep(3000);
  mt.start();
 }
}

  当线程对象mt运行完成后,我们让主线程休息一下,然后我们再次在这个线程对象上启动线程。结果我们看到:

  Exception in thread "main" java.lang.IllegalThreadStateExcept ion

  也就是这种线程对象一时运行一次完成后,它就再也不能运行第二次了。我们可以看一下它有具体实现:

public synchronized void start() {
 if (started)
  throw new IllegalThreadStateException();
  started = true;
  group.add(this);
  start0();
 }

  一个Thread的实例一旦调用start()方法,这个实例的started标记就标记为true,事实中不管这个线程后来有没有执行到底,只要调用了一次start()就再也没有机会运行了,这意味着:

  [通过Thread实例的start(),一个Thread的实例只能产生一个线程]

  那么如果要在一个实例上产生多个线程(也就是我们常说的线程池),我们应该如何做呢?这就是Runnable接口给我们带来的伟大的功能。

class R implements Runnable{
 private int x = 0;
 public void run(){
  for(int i=0;i<100;i++){
    try{
     Thread.sleep(10);
    }catch(Exception e){}
    System.out.println(x++);
  }
 }
}

  正如它的名字一样,Runnable的实例是可运行的,但它自己并不能直接运行,它需要被Thread对象来包装才行运行:

public class Test {
 public static void main(String[] args) throws Exception{
  new Thread(new R()).start();
 }
}

  当然这个结果和mt.start()没有什么区别。但如果我们把一个Runnable实例给Thread对象多次包装,我们就可以看到它们实际是在同一实例上启动线程:

public class Test {
 public static void main(String[] args) throws Exception{
  R r = new R();
  for(int i=0;i<10;i++)
    new Thread(r).start();
 }
}

  x是实例对象,但结果是x被加到了999,说明这10个线程是在同一个r对象上运行的。请大家注意,因为这个例子是在单CPU上运行的,所以没有对多个线程同时操作共同的对象进行同步。这里是为了说明的方便而简化了同步,而真正的环境中你无法预知程序会在什么环境下运行,所以一定要考虑同步。

  到这里我们做一个完整的例子来说明线程产生的方式不同而生成的线程的区别:

package debug;
import java.io.*;
import java.lang.Thread;
class MyThread extends Thread{
 public int x = 0;
 public void run(){
  System.out.println(++x);
 }
}

class R implements Runnable{
 private int x = 0;
 public void run(){
  System.out.println(++x);
 }
}
public class Test {
 public static void main(String[] args) throws Exception{
  for(int i=0;i<10;i++){
    Thread t = new MyThread();
    t.start();
  }
  Thread.sleep(10000);//让上面的线程运行完成
  R r = new R();
  for(int i=0;i<10;i++){
    Thread t = new Thread(r);
    t.start();
  }
 }  
}

  上面10个线程对象产生的10个线程运行时打印了10次1。下面10个线程对象产生的10个线程运行时打印了1到10。我们把下面的10个线程称为同一实例(Runnable实例)的多个线程。
<think>我们正在讨论Java中`implements``extends`的区别。 根据引用内容,我们可以总结以下几点: 1. `extends`用于继承一个类(父类),继承后可以使用父类的方法,也可以重写父类的方法。但Java不支持多重继承,所以一个类只能直接继承一个父类。 2. `implements`用于实现一个或多个接口,接口中的方法一般是空的,所以实现接口时必须重写接口中的所有方法。 3. 一个类只能继承一个类(单继承),但可以实现多个接口(多实现)。 因此,我们可以这样组织回答: 首先,解释`extends``implements`的基本概念用法。 然后,通过代码示例展示两者的使用。 最后,总结关键区别。 注意:使用中文回答,代码块使用正确格式,行内公式(如果有)用$...$,独立公式用$$...$$(但这个问题可能不太需要数学公式,所以可以省略公式部分)。 同时,生成相关问题。 根据引用,我们还可以补充: - 继承(extends)的类可以是普通类(非final且非abstract)或者是抽象类(abstract class)。 - 接口(interface)通过implements实现,一个类实现接口就必须实现接口中声明的所有方法(除非这个类是抽象类,那么它可以不实现全部方法,但最终必须有非抽象子类实现所有方法)。 我们还可以提到: - 接口可以多继承接口(即一个接口可以extends多个接口),但类只能单继承。 - 从Java 8开始,接口可以有默认方法(default method)静态方法(static method),这样在实现接口时,对于默认方法可以选择重写也可以不重写。 但是,用户的问题集中在类接口的区别上,所以我们主要围绕类接口的实现与继承来回答。 下面开始回答:</think>### Java中`implements``extends`的区别详解 在Java中,`implements``extends`是两个核心关键字,用于实现面向对象编程的继承多态特性。它们的核心区别如下: #### 1. **继承关系(`extends`)** - **作用**:用于类继承另一个类(单继承),或接口继承另一个接口(多继承)。 - **特点**: - 子类继承父类的属性方法(非`private`成员)。 - 子类可直接使用父类方法,也可重写(`@Override`)父类方法。 - **类继承**:Java仅支持单继承,即一个类只能直接继承一个父类。 ```java class Animal { void eat() { System.out.println("Eating..."); } } class Dog extends Animal { // Dog继承Animal(单继承) @Override void eat() { System.out.println("Dog eats bones"); } // 重写父类方法 } ``` - **接口继承**:接口可通过`extends`继承多个父接口。 ```java interface A { void methodA(); } interface B { void methodB(); } interface C extends A, B { } // 接口多继承 ``` #### 2. **接口实现(`implements`)** - **作用**:用于类实现一个或多个接口。 - **特点**: - 类必须重写接口中所有抽象方法(除非自身是抽象类)。 - 支持**多实现**:一个类可实现多个接口。 ```java interface Swimmer { void swim(); } interface Flyer { void fly(); } class Duck implements Swimmer, Flyer { // 多实现 @Override public void swim() { System.out.println("Duck swimming"); } @Override public void fly() { System.out.println("Duck flying"); } } ``` #### 3. **关键区别总结** | 特性 | `extends` (继承) | `implements` (实现) | |---------------------|--------------------------------------|-----------------------------------| | **目标对象** | 类继承类,或接口继承接口 | 类实现接口 | | **数量限制** | 类:单继承;接口:多继承 | 类可多实现(多个接口) | | **方法处理** | 可直接使用/重写父类方法 | 必须重写接口所有抽象方法 | | **关系本质** | "is-a"关系(如`Dog`是`Animal`) | "can-do"关系(如`Duck`能游泳/飞行)| | **默认方法** | 子类无需强制重写父类非抽象方法 | 从Java 8起,接口可包含`default`方法,子类可选重写 | #### 4. **使用场景** - 用`extends`: - 需要复用现有类的代码逻辑。 - 建立父子类层级关系(如`Animal → Dog`)。 - 用`implements`: - 需要遵循多个行为契约(如既会飞又会游)。 - 实现多态(通过接口类型引用对象)。 > **设计原则**:优先使用接口(`implements`)实现多态,避免单继承局限;通过抽象类(`extends`)提供通用实现[^1][^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值