Java 多线程 线程创建

本文介绍了Java中实现多线程的三种方式:继承Thread类、实现Runnable接口和实现Callable接口。通过示例代码详细展示了每种方式的步骤,并对比了它们的特点和适用场景。重点强调了Callable接口能返回结果的优势,以及FutureTask在管理线程返回值中的作用。最后,讨论了实现接口优于继承Thread类的原因,如更好的代码复用和避免单继承限制。
摘要由CSDN通过智能技术生成

Thread类是java.lang包下的一个线程类,用来实现Java多线程。通过继承Thread类的方式来实现多线程非常简单,主要步骤如下:

(1)创建一个Thread线程类的子类(子线程),同时重写Thread类的run()方法;

(2)创建该子类的实例对象,并通过调用start()方法启动线程。

接下来通过一个案例来演示如何通过继承Thread类的方式来实现多线程,如文件1所示。

文件1 Example01.java

 1// 1、定义一个继承Thread线程类的子类
 2    class MyThread1 extends Thread {
 3        // 创建子线程类有参构造方法
 4        public MyThread1(String name) {
 5            super(name);
 6        }
 7        // 1.1、重写Thread类的run()方法
 8        public void run() {
 9            int i=0;
 10            while (i++ <5) { 
 11                System.out.println(Thread.currentThread().getName()
 12                                     +"的run()方法在运行");
 13            }
 14        }
 15    }
 16    public class Example01 {
 17        public static void main(String[] args) {
 18            // 2、创建MyThread1实例对象
 19            MyThread1 thread1=new MyThread1("thread1");
 20            // 2.1、调用start()方法启动线程
 21            thread1.start();
 22            // 创建并启动另一个线程myThread2
 23            MyThread1 thread2=new MyThread1("thread2"); 
 24            thread2.start();
 25        }
 26    }

因为Java只支持类的单继承,如果某个类已经继承了其他父类,就无法再继承Thread类来实现多线程。在这种情况下,就可以考虑通过实现Runnable接口的方式来实现多线程。

使用实现Runnable接口的方式来实现多线程的主要步骤如下:

(1)创建一个Runnable接口的实现类,同时重写接口中的run()方法;

(2)创建Runnable接口的实现类对象;

(3)使用Thread有参构造方法创建线程实例,并将Runnable接口的实现类的实例对象作为参数传入;

(4)调用线程实例的start()方法启动线程。

接下来通过一个案例来演示如何通过实现Runnable接口的方式来实现多线程,如文件1所示。

文件1 Example02.java

1    //1、定义一个实现Runnable接口的实现类
 2    class MyThread2 implements Runnable {
 3        // 1.1、重写Runnable接口的run()方法
 4        public void run() {
 5            int i=0;
 6            while (i++ <5) { 
 7                System.out.println(Thread.currentThread().getName()
 8                                     +"的run()方法在运行");
 9            }
 10        }
 11    }
 12    public class Example02 {
 13        public static void main(String[] args) {
 14            // 2、创建Runnable接口实现类的实例对象
 15            MyThread2 myThread2 = new MyThread2();
 16            // 3、使用Thread(Runnable target, String name)构造方法创建线程对象
 17            Thread thread1 = new Thread(myThread2,"thread1");
 18            // 4、调用线程对象的start()方法启动线程
 19            thread1.start();
 20            // 创建并启动另一个线程thread2
 21            Thread thread2 = new Thread(myThread2,"thread2");
 22            thread2.start();
 23        }
 24    }

通过Thread类和Runnable接口实现多线程时,需要重写run()方法,但是由于该方法没有返回值,因此无法从多个线程中获取返回结果。为了解决这个问题,从JDK 5开始,Java提供了一个新的Callable接口,来满足这种既能创建多线程又可以有返回值的需求。

通过Callable接口实现多线程的方式与Runnable接口实现多线程的方式一样,都是通过Thread类的有参构造方法传入Runnable接口类型的参数来实现多线程,不同的是,这里传入的是Runnable接口的子类FutureTask对象作为参数,而FutureTask对象中则封装带有返回值的Callable接口实现类。

使用实现Callable接口的方式来创建并启动线程实例的主要步骤如下:

(1)创建一个Callable接口的实现类,同时重写Callable接口的call()方法;

(2)创建Callable接口的实现类对象;

(3)通过FutureTask线程结果处理类的有参构造方法来封装Callable接口实现类对象;

(4)使用参数为FutureTask类对象的Thread有参构造方法创建Thread线程实例;

(5)调用线程实例的start()方法启动线程。

接下来通过一个案例来演示如何通过实现Callable接口的方式来实现多线程,如文件1所示。

文件1 Example03.java

 1    import java.util.concurrent.*;
 2    // 1、定义一个实现Callable接口的实现类
 3    class MyThread3 implements Callable<Object> {
 4        // 1.1、重写Callable接口的call()方法
 5        public Object call() throws Exception {
 6            int i = 0;
 7            while (i++ < 5) {
 8                System.out.println(Thread.currentThread().getName() 
 9                                    + "的call()方法在运行");
 10            }
 11            return i;
 12        }
 13    }
 14    
 15    public class Example03 {
 16        public static void main(String[] args) throws InterruptedException,
 17                                                        ExecutionException {
 18            // 2、创建Callable接口的实现类对象
 19            MyThread3 myThread3 = new MyThread3();
 20            // 3、使用FutureTask封装Callable接口
 21            FutureTask<Object> ft1 = new FutureTask<>(myThread3);
 22            // 4、使用Thread(Runnable target ,String name)构造方法创建线程对象
 23            Thread thread1 = new Thread(ft1, "thread1");
 24            // 5、调用线程对象的start()方法启动线程
 25            thread1.start();
 26            // 创建并启动另一个线程thread2
 27            FutureTask<Object> ft2 = new FutureTask<>(myThread3);
 28            Thread thread2 = new Thread(ft2, "thread2");
 29            thread2.start();
 30            // 可以通过FutureTask对象的方法管理返回值
 31            System.out.println("thread1返回结果:" + ft1.get());
 32            System.out.println("thread2返回结果:" + ft2.get());
 33        }
 34    }

Callable接口方式实现的多线程是通过FutureTask类来封装和管理返回结果的,该类的直接父接口是RunnableFuture,从名称上可以看出RunnableFuture是由Runnable和Future组成的结合体。下面就通过一个示意图来展示FutureTask类的继承关系,如图2所示。

图2 FutureTask继承关系图

从图2可以看出,FutureTask本质是Runnable接口和Future接口的实现类,而Future则是JDK 5提供的用来管理线程执行返回结果的。其中Future接口中共有5个方法,用来对线程结果进行管理,这些方法及说明如表1所示。

表1 Future接口的方法

方法声明功能描述
boolean cancel(boolean mayInterruptIfRunning)用于取消任务,参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行的任务
boolean isCancelled()判断任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true
boolean isDone()判断任务是否已经完成,若任务完成,则返回true
V get()用于获取执行结果,这个方法会发生阻塞,一直等到任务执行完毕才返回执行结果
V get(long timeout, TimeUnit unit)用于在指定时间内获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null

通过实现Runnable接口(或者Callable接口)相对于继承Thread类实现多线程来说,有如下显著的好处:

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值