最全面的创建线程的几种方式总结,让你的需求轻松选择最合适你的线程创建方式

在java进程中,每一个线程都对应着一个Thread实例,线程的描述信息都会保存在Thread实例属性中, 供JVM进行线程管理和调度时使用功能.Thread 类是java多线程编程的基础, 创建线程有以下4中方式:

  • 继承Thread类创建线程类
  • 实现Runnable接口创建线程目标类
  • 使用Callable 和FutureTask 创建线程
  • 通过线程池创建线程

继承Thread类创建线程类

继承Thread类创建线程类是java多线程编程的最基础的创建方式,继承Thread类的同时需要重写run()方法,将需要并发执行的业务代码编写在run()方法中,示例代码如下:

package com.th.thread;

/**
 * @ClassName: CreateDemo
 * @Description:
 * @Author: 唐欢
 * @Date: 2022/8/11 15:24
 * @Version 1.0
 */
public class CreateDemo {
    public  static final int MAX_TURE=5;

    public  static String getCurThreadName(){
        return  Thread.currentThread().getName();
    }

    //线程的编号
    static int threadNo=1;

    static class  DemoThread extends  Thread{
        public  DemoThread(){
            super("DemoThrea-"+threadNo++);
        }
        @Override
        public  void run(){
            for (int i=1;i<MAX_TURE;i++){
                System.out.println(getName()+",轮次:"+i);
            }
            System.out.println(getName() + "运行结束,哈哈");
        }
    }

    public static void main(String[] args) {
        Thread thread =null;

        //方法一:使用Thread子类创建和启动线程
        for (int i=0;i<2;i++){
            thread =new DemoThread();
            thread.start();
        }
        System.out.println(ThreadUtil.getCurThreadName() + "最终运行结束");
    }
}

运行结果如下:
在这里插入图片描述
从代码中可以看到,设计了一个静态内部类DemoThread,方便防伪外部类的成员属性和方法,静态内部类DemoThread 重写了Thread类的run()方法,并将需要并发执行的用户业务代码编写在重写的run()方法中.

在创建线程的时候继承Thread方法需要重写run()方法, 接下来我们就来看下Thread.run()方法的实现代码:
在这里插入图片描述
从代码中可看到,如果target(执行目标)不为空,就执行target属性的run方法.target 属性的定义如下:
在这里插入图片描述
target 属性是Thread 属性是Thread 类的一个实例属性,并且target属性的类型为Runable.

实现Runnable接口创建线程目标类

Runnable 是一个极为简单的接口,代码如下:
在这里插入图片描述
Runnable接口有且仅有一个抽象方法 run(),并被用注解@FunctionalInterface 标注为函数式接口. 在使用的时候,将用户业务逻辑编写在run()方法中. 当Runnable 实例传入Thread 实例的target属性后,Runnable 接口的run()的实现版本被异步调用.

我们先来看一个通过实现Runnable接口创建线程的示例:

package com.th.runnable;

import com.th.util.ThreadUtil;

/**
 1. @ClassName: CreateDemo
 2. @Description:
 3. @Author: 唐欢
 4. @Date: 2022/8/11 15:35
 5. @Version 1.0
 */
public class CreateDemo {

    public  static  final int MAX_TURN=5;

    static int threadNo=1;

    static  class RunTarget implements  Runnable{

        @Override
        public void run() {
            for (int j=1 ;j<MAX_TURN;j++){
                System.out.println(ThreadUtil.getCurThreadName()+",轮次:"+j);
            }
            System.out.println(ThreadUtil.getCurThreadName() +" 运行结束");
        }
    }

    public static void main(String[] args) {
        Thread  thread =null;
        for (int i=0;i<2;i++){
            Runnable targe =new RunTarget();
            //通过Thread 类创建线程对象,将Runnable 实例作为实际参数传入
            thread = new Thread(targe,"RunnableThread"+threadNo++);
            thread.start();
        }
    }
}

从示例代码中可看到,静态内部类RunTarget 执行目标类实现Runnable接口需要一部并发执行代码逻辑被编写在它的run()方法中.将Runnable 实例作为target 执行目标传入Thread实例. 具体实现步骤如下:
(1) 定义一个新类实现Runable接口;

(2) 实现runnable接口中的run()抽象方法,将线程代码逻辑存放在该run()实现版本中.

(3) 通过Thread类创建线程对象, 将Runnable 实例作为实际参数传递给Thread类的构造器,由Thread 构造器将该Runnable 实例赋值给自己的target 执行目标属性.

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

(5)线程启动之后,线程的run()方法将被JVM 执行,该run()方法将调用target 属性的run()方法,从而完成Runnable实现类中业务代码逻辑的并发执行.

使用Runnable 创建线程目标类除了直接实现Runnable 接口之外,还有两种比较优雅的实现方式,

通过匿名类创建Runnable线程目标类

在实现Runnable 接口创建线程目标类时,若target 实现类是一次性的,就可以使用匿名类实现,实现代码如下:

package com.th.runnable;

import com.th.util.ThreadUtil;

import java.time.chrono.ThaiBuddhistEra;

/**
 * @ClassName: CreateDemo2
 * @Description: 通过匿名类优雅地创建Runnable 线程目标类
 * @Author: 唐欢
 * @Date: 2022/8/11 16:21
 * @Version 1.0
 */
public class CreateDemo2 {
    public  static final int MAX_TURN=5;

    static int threadNo= 1;

    public static void main(String[] args) {
        Thread thread =null;

        //使用Runnable的匿名类创建和启动线程
        for (int i=0;i<2 ;i++){
            thread =new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j=1;j<MAX_TURN;j++){
                        System.out.println(ThreadUtil.getCurThreadName()+",轮次:"+j);
                    }
                    System.out.println(ThreadUtil.getCurThreadName()+"运行结束.");

                }
            },"RunnableThread "+threadNo++);
            thread.start();
        }
        System.out.println(ThreadUtil.getCurThreadName()+"最后运行结束了.");
    }
}

使用Lambda 表达式创建Runnable线程目标类.

通过Lambda 表达式直接编写Runnable 接口的run()方法的实现代码,接口名称(Runnable) ,方法名称run() 统统都被省略,仅剩下了run()方法的形参列表和方法体,示例代码如下:

package com.th.runnable;

import com.th.util.ThreadUtil;

import java.awt.image.ShortLookupTable;

/**
 * @ClassName: CreateLambdaDemo
 * @Description:
 * @Author: 唐欢
 * @Date: 2022/8/11 16:33
 * @Version 1.0
 */
public class CreateLambdaDemo {
    public  static final  int MAX_TURN =5;
    static int threadNo=1;

    public static void main(String[] args) {
        Thread thread =null;

        //使用Lambda 表达式形式创建和启动线程
        for (int i =0 ;i<2;i++){
            thread =new Thread(()->{
                for (int j=1;j<MAX_TURN;j++){
                    System.out.println(ThreadUtil.getCurThreadName() +",轮次:"+j);
                }
                System.out.println(ThreadUtil.getCurThreadName()+"运行结束.");
            },"RunnableThread"+threadNo++);


            thread.start();
        }
        System.out.println(ThreadUtil.getCurThreadName()+"最终运行结束了.");
    }

}

使用Callable 和FutureTask 创建线程

虽然说是使用Thread和Runnable可以创建线程,但是这两中方法有一个共同的缺点:不能获取异步执行的结果.

在jdk1.5 后,提供了一种新的多线程创建方法,通过Callable接口和FutureTask类相结合创建线程.

通过Callable接口和Future接口相结合创建多线程能够获取异步执行结果,创建线程的步骤如下:
(1) 创建一个Callable 接口的实现类,并实现其Call()方法,编写好异步执行的具体逻辑,可以有返回值,

(2) 使用Callable实现类的实例构造一个FutureTask 实例.\

(3) 使用FutureTask实例作为Thread构造器的target入参,构造新的Thread 线程示例.

(4)调用Thread 实例的start()方法启动新线程,启动新线程的run()方法并发执行.其内部的执行过程为:启动Thread实例的run()方法并发执行后,会执行FutureTask实例的run()方法,最终会并发执行Callable实现类的call()方法.

(5)调用FutureTask 对象的get() 方法阻塞性地获得并发线程的执行结果.

示例的代码如下:

package com.th.callableandfuture;

import com.th.util.ThreadUtil;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @ClassName: CreateDemo
 * @Description:
 * @Author: 唐欢
 * @Date: 2022/8/12 13:48
 * @Version 1.0
 */
public class CreateDemo {

    public static  final int MAX_TURE=5;

    public  static final int COMPUTE_TIME=100000000;

    /**
     * ① 创建一个Callable 接口的实现类
     */
    static  class ReturnalbleTask implements Callable<Long>{
            //② 编写好异步执行的具体逻辑,可以有返回值

        @Override
        public Long call() throws Exception {
           Long startTime = System.currentTimeMillis();
            System.out.println(ThreadUtil.getCurThreadName() +"线程运行开始,");
            Thread.sleep(1000);
            for (int i=0;i<COMPUTE_TIME;i++){
                int j= i*10000;
            }
            long used =System.currentTimeMillis()-startTime;
            System.out.println(ThreadUtil.getCurThreadName()+"线程运行结束");
            return  used;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ReturnalbleTask task = new ReturnalbleTask();
        FutureTask<Long> futureTask = new FutureTask<Long>(task);
        Thread thread = new Thread(futureTask,"returnableThread");

        thread.start();
        Thread.sleep(500);
        System.out.println(ThreadUtil.getCurThreadName()+"让子弹飞一会儿,");
        System.out.println(ThreadUtil.getCurThreadName()+"做一点自己的事情");
        for (int i=0;i<COMPUTE_TIME/2;i++){
            int j=i*10000;
        }
        System.out.println(ThreadUtil.getCurThreadName()+"获取并发任务的执行结果.");
        try {
            System.out.println(thread.getName()+"线程占用时间:"+futureTask.get());
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println(ThreadUtil.getCurThreadName()+"运行结束.");
    }
}

从示例代码中可知有两个线程,一个是执行main()方法的主线程main,另个是main线程通过Thread.start() 方法启动的业务线程ReturnalbleTask.main线程通过Thread.start()启动ReturnalbleTask线程之后,会继续做自己的事,ReturnalbleTask 线程开始并发执行, ReturnalbleTask 线程首先执行的是thread.run()方法,然后在其中会执行到target(futureTask任务) 的run()方法,接着在futureTask.run()方法中执行futureTask的callable成员的call()方法.FutureTask的callable成员的call()方法执行完成后,会将结果保存在FutureTask内部的outCome实例属性中.

main线程和returnableTask线程的执行流程大致如下:
在这里插入图片描述

通过线程池创建线程

前面三种方式创建的Thread实例在执行完成后就销毁了,这些线程实例都是不可复用的. 在高并发的应用常见下,是要求线程能够复用的,若想线程可以复用,就需要使用线程池技术.java中提供了了一个静态工厂来创建不同的线程池 --Executors工厂类.

使用Executors创建线程池,然后使用ExecutorService线程池执行或者提交target执行目标实例的示例代码如下:

package com.th.Executors;

import com.th.util.ThreadUtil;

import java.util.concurrent.*;

/**
 * @ClassName: CreateDemo
 * @Description:
 * @Author: 唐欢
 * @Date: 2022/8/12 14:18
 * @Version 1.0
 */
public class CreateDemo {

    public  static final int MAX_TURE=5;
    public  static final  int COMPUTE_TIMES=100000000;
    //创建一个包含三个线程的线程池
    private  static ExecutorService pool = Executors.newFixedThreadPool(3);

    static  class DemoThread implements  Runnable{

        @Override
        public void run() {
            for (int j=1;j<MAX_TURE;j++){
                System.out.println(ThreadUtil.getCurThreadName()+",轮次:"+j);
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    static  class ReturnableTask implements Callable<Long>{

        // 返回并发执行的时间
        @Override
        public Long call() throws Exception {
            Long startTime = System.currentTimeMillis();
            System.out.println(ThreadUtil.getCurThreadName() +"线程运行开始,");
            Thread.sleep(1000);
            for (int i=0;i<MAX_TURE;i++){
                int j= i*10000;
            }
            long used =System.currentTimeMillis()-startTime;
            System.out.println(ThreadUtil.getCurThreadName()+"线程运行结束");
            return  used;
        }
    }

    public  static void main(String[] args) throws ExecutionException, InterruptedException {
       //执行线程实例,无返回
        pool.execute(new DemoThread());
        pool.execute(new Runnable() {
            @Override
            public void run() {
                for (int j=1; j<MAX_TURE;j++){
                    System.out.println(ThreadUtil.getCurThreadName()+",轮次:"+j);
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        Future future = pool.submit(new ReturnableTask());
        Long result = (Long) future.get();
        System.out.println("异步任务的执行结果为:"+result);
        Thread.sleep(Integer.MAX_VALUE);
    }
}

补充ThreadUtil类的代码:

public class ThreadUtil {

    public  static  String getCurThreadName(){
        //获取线程名称
        return  Thread.currentThread().getName();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

弯_弯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值