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

 更新时间:2022年03月02日 16:59:05   作者:小小茶花女  
这篇文章主要为大家详细介绍了Java Runnable和Thread实现多线程哪个更好,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助<BR>

实现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去创建异步执行任务。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容! 

相关文章

  • 这么设置IDEA中的Maven,再也不用担心依赖下载失败了

    这么设置IDEA中的Maven,再也不用担心依赖下载失败了

    今天给大家带来一个IDEA中Maven设置的小技巧.这个技巧可以说非常有用,学会设置之后,再也不用担心maven依赖下载变慢的问题,需要的朋友可以参考下
    2021-05-05
  • 关于SpringCloud的Bus消息总线图文详解

    关于SpringCloud的Bus消息总线图文详解

    这篇文章主要介绍了关于SpringCloud的Bus消息总线图文详解,Spring Cloud Bus是用来将分布式系统的节点与轻量级消息系统链接起来的框架,它整合了Java的事件处理机制和消息中间件的功能,需要的朋友可以参考下
    2023-05-05
  • mybatis实现获取入参是List和Map的取值

    mybatis实现获取入参是List和Map的取值

    这篇文章主要介绍了mybatis实现获取入参是List和Map的取值问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • GC算法实现垃圾优先算法

    GC算法实现垃圾优先算法

    为什么会存在那么多的垃圾回收算法呢?我想这个问题的答案可能是没有任何一种内存回收算法是完美的,所以在针对不同的情景需求下,不同的内存回收算法有其独特的优势,所以最后就延续了多种回收算法
    2022-01-01
  • SpringBoot中配置文件pom.xml的使用详解

    SpringBoot中配置文件pom.xml的使用详解

    SpringBoot的pom.xml文件是Maven项目的核心配置文件,用于定义项目的依赖、插件、构建配置等信息,下面小编就来和大家详细介绍一下它的具体使用吧
    2025-03-03
  • 使用javassist动态生成类的配置代码

    使用javassist动态生成类的配置代码

    Javassist它是一个用 Java 编辑字节码的类库,它使 Java 程序能够在运行时定义新类,并在 JVM 加载时修改类文件,本文给大家介绍使用javassist动态生成类的实例代码,感兴趣的朋友一起看看吧
    2022-09-09
  • Mybatis如何配置连接池

    Mybatis如何配置连接池

    本文通过实例代码给大家详细介绍了mybatis配置连接池的方法,非常不错,具有参考借鉴价值,感兴趣的朋友参考下吧
    2016-12-12
  • Java基于正则实现的日期校验功能示例

    Java基于正则实现的日期校验功能示例

    这篇文章主要介绍了Java基于正则实现的日期校验功能,涉及java文件读取、日期转换及字符串正则匹配相关操作技巧,需要的朋友可以参考下
    2017-03-03
  • springboot中如何使用自定义两级缓存

    springboot中如何使用自定义两级缓存

    本话题主要就是讨论如何在springboot的基础上,无缝集成ehcache和redis作为一二级缓存,并且实现缓存同步。
    2021-05-05
  • Java游戏俄罗斯方块的实现实例

    Java游戏俄罗斯方块的实现实例

    这篇文章主要介绍了Java游戏俄罗斯方块的实现实例的相关资料,这里实现简单的俄罗斯方块帮助大家学习理解基础知识,需要的朋友可以参考下
    2017-08-08

最新评论