位置:首页 > Java > Java三种多线程实现方式对比与优缺点分析

Java三种多线程实现方式对比与优缺点分析

时间:2026-08-15  |  作者:云端旅人  |  阅读:0

多线程的三种实现方式与区别

多线程的实现方式有三种,其中Runnable接口和Callable接口实现多线程的方式基本相同,主要区别就是Callable接口中的方法有返回值,并且可以声明抛出异常。

那么通过继承Thread类和其他两种接口实现多线程的方式有什么区别呢?接下来通过一个应用场景来分析说明。

售票场景分析

不妨这样理解:售票厅里一共有四个窗口,同时对外发售某日某次列车的100张车票。

这100张车票就属于典型的共享资源,而这四个售票窗口,则可以对应看成四个线程。

为了把每个窗口的售票情况展示得更清楚,可以先通过Thread的currentThread()方法拿到当前线程的实例对象,再调用getName()方法获取线程名称。

接下来,就通过继承Thread类的方式来实现多线程,具体如文件1所示。

文件1 Example04.ja va

 1    // 1、定义一个继承Thread线程类的子类
 2    class TicketWindow extends Thread {
 3        private int tickets = 100;
 4        public void run() {
 5            while (true) { 
 6                if (tickets > 0) {
 7                    System.out.println(Thread.currentThread().getName()
 8                                         + " 正在发售第 " + tickets-- + " 张票 ");
 9                }
 10            }
 11        }
 12    }
 13    public class Example04 {
 14        public static void main(String[] args) {
 15            // 分别创建4个线程对象TicketWindow并开启,来模拟4个售票窗口
 16            new TicketWindow().start(); 
 17            new TicketWindow().start(); 
 18            new TicketWindow().start(); 
 19            new TicketWindow().start(); 
 20        }
 21    }

运行结果如图1所示。

Java三种多线程实现方式对比与优缺点分析_wishdown.com

图1 运行结果

继承Thread类存在的问题

从图1不难看出,同一张票实际上被卖了四遍

问题就出在资源没有共享上:这四个线程拿的并不是同一份100张票,而是各自带着100张票在卖。

程序里一共创建了四个TicketWindow对象,这就相当于同时启用了四套彼此独立的售票逻辑。

而且每个TicketWindow对象内部都维护着一个tickets票据变量。这样一来,线程执行任务时处理的都是各自那份资源,自然不会去共同操作同一个售票资源。

小提示

文件1中创建并启动4个线程时并没有指定线程的名称,但运行结果却显示有Thread-0、Thread-1...这样的线程名称。

这是因为,在创建多线程时如果没有通过构造方法指定线程名称,则系统默认生成线程名称。

为什么更适合使用Runnable接口

由于现实中,售票系统中的票资源是共享的,因此上面的运行结果显然不合理。

为了保证售票资源共享,在程序中只能创建一个售票对象,然后开启多个线程去共享同一个售票对象来执行售票方法。

简单来说就是四个线程运行同一个售票程序,这时就需要通过实现Runnable接口的方式来实现多线程。

接下来将文件1进行修改,并使用构造方法Thread(Runnable target, String name)在创建线程对象的同时指定线程的名称,如文件2所示。

文件2 Example05.ja va

 1    // 定义一个实现Runnable接口的实现类
 2        class TicketWindow2 implements Runnable {
 3        private int tickets = 100;
 4        public void run() {
 5            while (true) {
 6                if (tickets > 0) {
 7                    System.out.println(Thread.currentThread().getName()
 8                                         + " 正在发售第 " + tickets-- + " 张票 ");
 9                }
 10            }
 11        }
 12    }
 13    public class Example05 {
 14        public static void main(String[] args) {
 15            // 创建TicketWindow实例对象tw
 16            TicketWindow2 tw = new TicketWindow2(); 
 17            // 分别创建4个线程对象同时进行命名,并开启线程
 18            new Thread(tw, "窗口1").start();      
 19            new Thread(tw, "窗口2").start();      
 20            new Thread(tw, "窗口3").start();     
 21            new Thread(tw, "窗口4").start();      
 22        }
 23    }

运行结果如图2所示。

Java三种多线程实现方式对比与优缺点分析_wishdown.com

图2 运行结果

实现Runnable接口后的效果

文件2中,通过实现Runnable接口的方式只创建了一个TicketWindow2对象,然后创建了四个线程。

在每个线程上都调用同一个TicketWindow2对象中的run()方法,这样就可以确保四个线程访问的是同一个tickets变量,共享100张车票。

Runnable接口或Callable接口的优势

通过上面的售票案例,并结合实际情况进行分析,通过实现Runnable接口(或者Callable接口)相对于继承Thread类实现多线程来说,有如下显著的好处:

  • 适合多个线程去处理同一个共享资源的情况,把线程同程序代码、数据有效的分离,很好的体现了面向对象的设计思想。

  • 可以避免Ja va单继承带来的局限性,由于一个类不能同时有两个父类,所以在当前类已经有一个父类的基础上,那么就只能采用实现Runnable接口或者Callable接口的方式来实现多线程。

结论

事实上,实际开发中大部分的多线程应用都会采用Runnable接口或者Callable接口的方式实现多线程。

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多