前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >多线程(一)-两种创建线程的方式+实现Callable接口方式

多线程(一)-两种创建线程的方式+实现Callable接口方式

作者头像
化羽羽
发布2022-10-28 11:36:49
2850
发布2022-10-28 11:36:49
举报
文章被收录于专栏:化羽学Java

大佬的理解->Java多线程(一)多线程基础

大佬的理解->Java多线程(二)常用的实现多线程的两种方式

1、继承Thread类

​ 继承Thread必须重写run方法,(具体业务执行方法,需要执行的业务方法,定义在此方法中),注意此方法是线程启动后线程自动调用的;

案例

代码语言:javascript
复制
public class MyThread extends Thread{

    @Override
    public void run() {
        //线程执行的业务方法
        System.out.println("子线程执行");
        for (int i = 0;i < 5;i++){
            System.out.println("--- 线程名---:"+Thread.currentThread().getName()+",序号:"+i);
        }
    }

    public static void main(String[] args) {
        //主线程
        System.out.println("***主线程执行***");
        System.out.println("***线程名***:"+Thread.currentThread().getName());

        //创建一个线程并启动,只能通过主线程创建其他线程
        MyThread thread1 = new MyThread();
        MyThread thread2 = new MyThread();

        //启动线程:start()方法(一旦启动,自动启动子线程,当前线程继续向下执行,不会等子线程)
        thread1.start();

        //启动多线程
        //多线程并发执行:不是正真一样上的并行执行(肉眼感官是并行),而是通过cpu的调度算法,有序cpu执行极快,所以肉眼看起来是并行的;
        thread2.start();

        //调用run方法,不可以启动线程,就是对象的普通方法调用,等run方法执行结束,主线程才能继续执行
        //thread1.run();
        //thread2.run();

        System.out.println("----主线程执行结束----");

    }
}

运行结果

调用start()方法

代码语言:javascript
复制
***主线程执行***
***线程名***:main
----主线程执行结束----
子线程执行
--- 线程名---:Thread-0,序号:0
--- 线程名---:Thread-0,序号:1
--- 线程名---:Thread-0,序号:2
--- 线程名---:Thread-0,序号:3
--- 线程名---:Thread-0,序号:4
子线程执行
--- 线程名---:Thread-1,序号:0
--- 线程名---:Thread-1,序号:1
--- 线程名---:Thread-1,序号:2
--- 线程名---:Thread-1,序号:3
--- 线程名---:Thread-1,序号:4

调用run()方法

代码语言:javascript
复制
***主线程执行***
***线程名***:main
子线程执行
--- 线程名---:main,序号:0
--- 线程名---:main,序号:1
--- 线程名---:main,序号:2
--- 线程名---:main,序号:3
--- 线程名---:main,序号:4
子线程执行
--- 线程名---:main,序号:0
--- 线程名---:main,序号:1
--- 线程名---:main,序号:2
--- 线程名---:main,序号:3
--- 线程名---:main,序号:4
----主线程执行结束----      //必须等子线程完成后才可以继续运行

注意start()方法和run()方法的区别

start():启动线程start()方法(一旦启动,自动启动子线程,当前线程继续向下执行,不会等子线程); run() :调用run方法,不可以启动线程,只是对象的普通方法调用,等run方法执行结束,主线程才能继续执行;

2、实现Runnable接口

实现Runnable接口,也必须实现run方法;

案例

代码语言:javascript
复制
public class MyRunnable implements Runnable{

    private int num = 5;

    @Override
    public void run() {
        //线程执行的业务方法
        System.out.println("子线程执行");
        for (int i = 0;i < 5 ;i++){
            if(num>0){
                System.out.println("--- 线程名---:"+Thread.currentThread().getName()+",序号:"+num--);
            }
        }
    }

    public static void main(String[] args) {
        //主线程
        System.out.println("***主线程执行***");
        System.out.println("***线程名***:"+Thread.currentThread().getName());

        //创建一个子线程,并启动
        MyRunnable runnable1 = new MyRunnable();

        //实现Runnable接口方式创建的线程,不能自己启动,只能通过Thread类,将Runnable作为参数传入Thread类的构造方法中,
        // 构造线程对象,才可以启动
        Thread thread1 = new Thread(runnable1);
        thread1.start();
        //创建多线程 (如果传入的Runnable参数一样,可以共享资源)
        Thread thread2 = new Thread(runnable1);
        thread2.start();

        System.out.println("----主线程执行结束----");

    }

}

运行结果

代码语言:javascript
复制
***主线程执行***
***线程名***:main
----主线程执行结束----
子线程执行
子线程执行
--- 线程名---:Thread-0,序号:5
--- 线程名---:Thread-1,序号:4
--- 线程名---:Thread-0,序号:3
--- 线程名---:Thread-1,序号:2
--- 线程名---:Thread-0,序号:1

注意

如果传入的Runnable参数一样,可以共享资源;

3、比较两种创建线程的方式

继承Thread类

  • 编写简单,可直接操作线程
  • 适用于单继承

实现Runnable接口

  • 避免单继承局限性
  • 便于共享资源

4、实现Callable接口

4.1实现Callable接口调用的call方法

创建线程的方式三,实现Callable接口,线程自动调用的时call方法,不是run方法,jdk1.5后才提供;

4.2 FutureTask 类的继承关系

执行 Callable 方式,需要 FutureTask 实现类的支持,用于接收运算结果。

代码语言:javascript
复制
//FutureTask<V> 是 RunnableFuture<V> 的实现类
public class FutureTask<V> implements RunnableFuture<V> ;
//RunnableFuture<V> 接口继承了 Runnable, Future<V>          //所以FutureTask最后需要放到Thread参数中,这里跟继承Runnable方法一样;
public interface RunnableFuture<V> extends Runnable, Future<V> ;

类图

img
img

4.3 案例

代码语言:javascript
复制
public class MyCallable implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        System.out.println("***子线程执行***");
        //执行线程处理方法
        int sun = 0;
        for (int i = 0; i < 5; i++) {
            sun+=i;
        }
        return sun;
    }

    public static void main(String[] args) {
        //主线程执行
        System.out.println("---主线程执行---");

        //创建子线程,不可以自己单独启动,必须借助FutureTask才可以,必须获取子线程执行结果
        MyCallable callable = new MyCallable();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);

        //启动线程,只能借助Thread类
        Thread thread = new Thread(futureTask);
        thread.start();

        //获取子线程的执行结果(必须要子线程执行结束,才可以获取结果)
        try {
            Integer resultSun = futureTask.get(); //接收返回值
            System.out.println("五以内的数字之和:"+resultSun);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("---主线程结束---");

    }
}

运行结果

代码语言:javascript
复制
---主线程执行---
***子线程执行***
五以内的数字之和:10  //接收到返回值
---主线程结束---

4.4 Callable和Runnable的区别

1)所在包不同,Callable在java.util.concurrent包下,Runnable在java.lang包;

2)实现的接口方法不同:Callable是重写call方法,Runnable的重写run方法;

3)抛出异常处理不同:Callable是重写call方法,可以抛出异常,但是Runnable是重写run方法不可以抛出异 常,如果抛出线程直接中断;

4)返回值不同:实现Callable接口的线程,可以通过FutureTask获取返回值,但是是实现Runnable接口的线程,无法获取返回值;

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-06-20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、继承Thread类
  • 2、实现Runnable接口
  • 3、比较两种创建线程的方式
  • 4、实现Callable接口
    • 4.1实现Callable接口调用的call方法
      • 4.2 FutureTask 类的继承关系
        • 4.3 案例
          • 4.4 Callable和Runnable的区别
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档