Java Runnable和Thread实现多线程哪个更好你知道吗

作者:小小茶花女 时间:2021-08-17 05:48:50 

实现Runnable 接口比继承Thread 类的方式更好:

(1)可以避免由于Java单继承带来的局限性;

(2)可以实现业务执行逻辑和数据资源的分离;

(3)可以与线程池配合使用,从而管理线程的生命周期;

1. 避免由于Java单继承带来的局限性

如果异步逻辑所在类已经继承了一个基类,就没有办法再继承Thread类。比如,当一个Dog类继承了Pet类,再要继承Thread类就不行了。所以在已经存在继承关系的情况下,只能使用实现Runnable接口的方式。

public class ThreadTask extends Thread {
   // 线程的执行体
   @Override
   public void run() {
       System.out.println("线程执行的任务");
   }
}
public class RunnableTask implements Runnable {
   // 线程的执行体
   @Override
   public void run() {
       System.out.println("线程执行的任务");
   }
}

2. 可以实现业务执行逻辑和数据资源的分离

逻辑和数据更好分离。通过实现Runnable接口的方法创建多线程更加适合同一个资源被多段业务逻辑并行处理的场景。在同一个资源被多个线程逻辑异步、并行处理的场景中,通过实现Runnable接口的方式设计多个target执行目标类可以更加方便、清晰地将执行逻辑和数据存储分离,更好地体现了面向对象的设计思想。

注意:并不是继承Thread类不能实现资源共享,而是没有实现Runnable接口更方便,更清晰,他们两的主要区别就是类和接口的区别,但是我们一般多用Runnable。

(1) 通过继承Thread类的方式实现多线程,数据资源和业务执行逻辑是耦合在一起的, 多个线程并发地完成各自的任务,访问各自的数据资源,而不是共享一份数据资源:

public class ThreadDemo extends Thread {
   // 数据资源
   private int ticket = 3;
   // 业务执行逻辑
   @Override
   public void run() {
       for(int i=0;i<3;i++){
           if(ticket>0){
               System.out.println(Thread.currentThread().getName()+" 卖票--->"+ ticket--);
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
       }
       System.out.println(Thread.currentThread().getName()+" 线程运行结束");
   }
   public static void main(String[] args) throws InterruptedException {
       // 创建2个线程,分别去执行线程体中的业务逻辑
       Thread thread1 = new ThreadDemo();
       thread1.start();
       Thread thread2 = new ThreadDemo();
       thread2.start();
       Thread.sleep(1000);
       System.out.println("main线程运行结束");
   }
}

多个线程并发地完成各自的任务,访问各自的数据资源:

Thread-0 卖票--->3
Thread-1 卖票--->3
main线程运行结束
Thread-0 卖票--->2
Thread-1 卖票--->2
Thread-1 卖票--->1
Thread-0 卖票--->1
Thread-0 线程运行结束
Thread-1 线程运行结束

(2) 通过继承Thread类可以实现资源共享:

public class ThreadTask {
   private int ticket = 3;
   public synchronized void saleTicket(){
       for(int i=0;i<3;i++){
           if(ticket>0){
               System.out.println(Thread.currentThread().getName()+" 卖票--->"+ticket--);
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
       }
       System.out.println(Thread.currentThread().getName()+" 线程运行结束");
   }
}
public class ThreadA extends Thread {
   ThreadTask threadTask ;
   public ThreadA(ThreadTask threadTask){
       super();
       this.threadTask = threadTask;
   }
   @Override
   public void run() {
       threadTask.saleTicket();
   }
}
public class ThreadB extends Thread {
   ThreadTask threadTask ;
   public ThreadB(ThreadTask threadTask){
       super();
       this.threadTask = threadTask;
   }
   @Override
   public void run() {
       threadTask.saleTicket();
   }
}
public class Main {
   public static void main(String[] args) throws InterruptedException {
       ThreadTask threadTask = new ThreadTask();
       ThreadA t1 = new ThreadA(threadTask);
       ThreadB t2 = new ThreadB(threadTask);
       t1.start();
       t2.start();
   }
}

执行结果:

Thread-0 卖票--->3
Thread-1 卖票--->2
Thread-1 卖票--->1
Thread-0 线程运行结束
Thread-1 线程运行结束

(3) 通过实现Runnable接口实现多线程,能更好地做到多个线程并发地完成同一个任务,访问同一份数据资源。多个线程的代码逻辑可以方便地访问和处理同一个共享数据资源 ,这样可以将线程逻辑和业务数据进行有效的分离,更好地体现了面向对象的设计思想。

public class RunnableDemo{
   public static class RunnableTask  implements Runnable{
       // 数据资源
       private int ticket = 3;
       // 线程执行体
       @Override
       public synchronized void run() {
           for(int i=0;i<3;i++){
               if(ticket>0){
                   System.out.println(Thread.currentThread().getName()+" 卖票--->"+ticket--);
                   try {
                       Thread.sleep(1000);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
               }
           }
           System.out.println(Thread.currentThread().getName()+" 线程运行结束");
       }
   }
   public static void main(String[] args) {
       // 将这一个target作为参数传给两个线程,那么这两个线程执行的都是这个target的run()方法
       Runnable target = new RunnableTask();
       // 创建两个线程执行target的线程体
       Thread thread1 = new Thread(target,"thread1");
       thread1.start();
       Thread thread2 = new Thread(target,"thread2");
       thread2.start();
       System.out.println("main线程运行结束");
   }
}

多个线程并发地完成同一个任务,访问同一份数据资源:

main线程运行结束
thread1 卖票--->3
thread1 卖票--->2
thread1 卖票--->1
thread1 线程运行结束
thread2 线程运行结束

3. 可以与线程池配合使用,从而管理线程的生命周期

实现Runnable接口来实现线程,执行目标类,更容易和线程池配合使用,异步执行任务在大多数情况下是通过线程池去提交的,而很少通过创建一个新的线程去提交,所以更多的做法是,通过实现Runnable接口创建异步执行任务,而不是继承Thread去创建异步执行任务。

来源:https://hengheng.blog.csdn.net/article/details/123008089

标签:Java,Runnable,Thread,多线程
0
投稿

猜你喜欢

  • java实现大文件分割与合并的实例代码

    2023-11-11 04:31:21
  • Spring学习笔记之bean的基础知识

    2021-09-08 10:09:27
  • SpringBoot如何通过Feign调用传递Header中参数

    2023-11-24 21:39:29
  • 解决idea web 配置相对路径问题

    2022-01-12 06:48:40
  • Java使用pulsar-flink-connector读取pulsar catalog元数据代码剖析

    2023-11-05 17:25:41
  • C++容器适配与栈的实现及dequeque和优先级详解

    2023-11-02 12:57:52
  • Spring Bean常用依赖注入方式详解

    2022-06-05 21:43:33
  • Swagger实现动态条件注入与全局拦截功能详细流程

    2023-11-23 13:41:05
  • Java面向对象程序设计:类的定义,静态变量,成员变量,构造函数,封装与私有,this概念与用法详解

    2022-07-12 03:35:14
  • IDEA+JRebel实现全自动热部署的方法步骤

    2023-11-29 13:53:30
  • java基础的详细了解第九天

    2022-11-11 20:53:50
  • Java实现分页代码

    2023-08-05 08:14:47
  • Springboot之idea之pom文件图标不对问题

    2021-12-31 07:27:32
  • Spring @Profile注解详解

    2023-04-20 06:26:16
  • 新手初学Java集合框架

    2022-10-06 03:01:51
  • java设计模式之工厂模式实例详解

    2023-11-24 23:35:12
  • Android+SQLite数据库实现的生词记事本功能实例

    2023-06-18 10:41:35
  • java中的session对象及其常用方法小结

    2023-11-25 02:31:33
  • javaWeb项目部署到阿里云服务器步骤详解

    2023-11-07 05:21:36
  • C++实现的链表类实例

    2023-07-04 08:36:36
  • asp之家 软件编程 m.aspxhome.com