【JUC】继承Thread类与实现Runnable接口的两种创建线程方式有什么区别?

Runnable与Thread的区别

1. 继承关系不同

1.1 继承Thread类

// 直接继承Thread类
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("线程执行中...");
    }
}

// 使用
MyThread thread = new MyThread();
thread.start();

1.2 实现Runnable接口

// 实现Runnable接口
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("线程执行中...");
    }
}

// 使用
Thread thread = new Thread(new MyRunnable());
thread.start();

2. 主要区别对比

特性继承Thread类实现Runnable接口
继承限制占用了唯一的继承机会,无法再继承其他类不占用继承机会,可以继承其他类
代码复用线程和任务绑定在一起,复用性差任务与线程分离,复用性好
资源共享多个线程需要创建多个对象实例多个线程可以共享同一个Runnable实例
设计原则不符合面向对象设计原则符合"组合优于继承"的原则
复杂度相对简单直接需要创建Thread对象来包装

3. 资源共享的差异

3.1 继承Thread方式 - 资源不共享

class TicketThread extends Thread {
    private int tickets = 5; // 每个线程都有自己的tickets
    
    @Override
    public void run() {
        while(tickets > 0) {
            System.out.println(getName() + "卖出票号:" + tickets--);
        }
    }
}

// 测试 - 每个线程独立售票,总共卖出15张票
new TicketThread().start();
new TicketThread().start();
new TicketThread().start();

3.2 继承Thread方式 - 资源不共享

class TicketRunnable implements Runnable {
    private int tickets = 5; // 多个线程共享同一个tickets
    
    @Override
    public void run() {
        while(tickets > 0) {
            System.out.println(Thread.currentThread().getName() + "卖出票号:" + tickets--);
        }
    }
}

// 测试 - 三个线程共享5张票
TicketRunnable task = new TicketRunnable();
new Thread(task, "窗口1").start();
new Thread(task, "窗口2").start();
new Thread(task, "窗口3").start();

4. 使用场景

4.1 适合继承Thread的场景

  • 需要重写Thread类的方法(如interrupt()等)
  • 简单的单线程任务,不需要复杂的类层次结构
  • 快速原型开发

4.2 适合实现Runnable的场景(推荐)

  • 需要继承其他类
  • 需要在线程间共享资源
  • 使用线程池(线程池只能接受Runnable或Callable任务)
  • 符合面向对象设计原则
  • 复杂的业务逻辑处理

5. 现代开发的最佳实践

5.1 使用Lambda表达式(Java 8+)

// 更简洁的写法
new Thread(() -> {
    System.out.println("使用Lambda创建线程");
}).start();

5.2 使用线程池 + Runnable

ExecutorService executor = Executors.newFixedThreadPool(5);

// 提交Runnable任务
executor.execute(() -> {
    System.out.println("线程池执行任务");
});

executor.shutdown();

5.3 实现Callable接口(有返回值)

class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "任务执行结果";
    }
}

// 使用
Future<String> future = executor.submit(new MyCallable());
String result = future.get();

6. 总结

实现Runnable接口是更被推荐的方式,主要原因:

  1. 灵活性更高: 不占用继承位置,可以继承其他类
  2. 资源共享方便: 多个线程可以共享同一个Runnable实例
  3. 符合设计原则: 任务与执行机制分离
  4. 与现代API兼容: 线程池、CompletableFuture等都接受Runnable
  5. 代码更清晰: 业务逻辑与线程控制分离

在实际开发中,除非有特殊需求需要重写Thread类的方法,否则都应该优先选择实现Runnable接口的方式来创建线程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Craaaayon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值