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实现文件上传下载功能

    2021-11-26 17:19:05
  • C#中属性和成员变量的区别说明

    2022-02-17 22:36:57
  • Java后台通过Collections获取list集合中最大数,最小数代码

    2023-03-15 19:53:05
  • Android创建与解析XML(二)——详解Dom方式

    2023-08-20 02:30:05
  • 新版Android Studio3.6找不到R.java怎么处理

    2023-11-28 14:04:03
  • 基于C++实现的哈夫曼编码解码操作示例

    2023-10-13 13:02:43
  • Android实现波浪球效果

    2021-09-02 16:07:53
  • Spring Security使用中Preflight请求和跨域问题详解

    2021-06-12 11:04:15
  • Android启动页优化之实现应用秒开

    2021-05-27 23:51:32
  • java 进制转换实例详解

    2023-07-05 11:53:45
  • c# 用Base64实现文件上传

    2023-12-20 00:52:11
  • Android Fragment的回退栈示例详细介绍

    2023-06-21 12:30:55
  • Android 实现把bitmap图片的某一部分的颜色改成其他颜色

    2022-12-28 00:12:03
  • java poi导出图片到excel示例代码

    2023-10-30 00:13:17
  • JMeter中的后端监听器的实现

    2022-07-24 17:58:35
  • Mac中配置gradle环境及使用android studio打包jar包与arr包的方法

    2022-12-08 00:07:18
  • Java开发利器之Guava Cache的使用教程

    2022-03-20 19:22:02
  • Java读写文件创建文件夹多种方法示例详解

    2022-11-17 01:08:48
  • Sprint Boot 集成MongoDB的操作方法

    2022-11-13 07:10:37
  • JAVA中数组从小到大排序的2种方法实例

    2021-10-09 09:46:18
  • asp之家 软件编程 m.aspxhome.com