Java多线程(2)

Java多线程(2)

Java并发编程:Java实现多线程的几种方式

在Java中,多线程主要的实现方式有四种:继承Thread类、实现Runnable接口、实现Callable接口经过FutureTask包装器来建立Thread线程、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,然后两种是带返回值的。除此以外,经过Timer启动定时任务,或者经过像Spring Task和quartz这样的第三方任务调度框架也能够开启多线程任务。java

一、继承Thread类建立线程

Thread类本质上也是实现了Runnable接口的一个实例,表明一个线程的实例。启动线程的惟一方法就是经过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程比较简单,经过继承Thread类并复写run()方法,就能够启动新线程并执行本身定义的run()方法。多线程

CreateThreadDemo1.java并发

java 复制代码
public class CreateThreadDemo1 extends Thread {

    public CreateThreadDemo1(String name) {
        // 设置当前线程的名字
        this.setName(name);
    }

    @Override
    public void run() {
        System.out.println("当前运行的线程名为: " + Thread.currentThread().getName());
    }

    public static void main(String[] args) throws Exception {
        // 注意这里,要调用start方法才能启动线程,不能调用run方法
        new CreateThreadDemo1("MyThread1").start();
        new CreateThreadDemo1("MyThread2").start();

    }

}

二、实现Runnable接口建立线程

因为Java是单继承机制,若是本身的类已经继承自另外一个类,则没法再直接继承Thread类,此时,能够经过实现Runnable接口来实现多线程。异步

实现Runnable接口并实现其中的run方法,而后经过构造Thread实例,传入Runnable实现类,而后调用Thread的start方法便可开启一个新线程。ide

CreateThreadDemo2.javathis

java 复制代码
public class CreateThreadDemo2 implements Runnable {

    @Override
    public void run() {
        System.out.println("当前运行的线程名为: " + Thread.currentThread().getName());
    }

    public static void main(String[] args) throws Exception {
        CreateThreadDemo2 runnable = new CreateThreadDemo2();
        new Thread(runnable, "MyThread1").start();
        new Thread(runnable, "MyThread2").start();

    }

}

三、实现Callable接口经过FutureTask包装器来建立Thread线程线程

首先须要一个实现Callable接口的实例,而后实现该接口的惟一方法call逻辑,接着把Callable实例包装成FutureTask传递给Thread实例启动新线程。FutureTask本质上也实现了Runnable接口,因此一样能够用来构造Thread实例。

CreateThreadDemo3.java

java 复制代码
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class CreateThreadDemo3 {

    public static void main(String[] args) throws Exception {
        // 建立线程任务,lambada方式实现接口并实现call方法
        Callable<Integer> callable = () -> {
            System.out.println("线程任务开始执行了...");
            Thread.sleep(2000);
            return 1;
        };

        // 将任务封装为FutureTask
        FutureTask<Integer> task = new FutureTask<>(callable);

        // 开启线程,执行线程任务
        new Thread(task).start();

        // ====================
        // 这里是在线程启动以后,线程结果返回以前
        System.out.println("线程启动以后,线程结果返回以前...");
        // ====================

        // 随心所欲完毕以后,拿到线程的执行结果
        Integer result = task.get();
        System.out.println("主线程中拿到异步任务执行的结果为:" + result);

    }

}

四、使用ExecutorService、Callable、Future实现有返回结果的线程(线程池方式)

ExecutorService、Callable、Future三个接口都是属于Executor框架。可返回值的任务必须实现Callable接口。经过ExecutorService执行Callable任务后,能够获取到一个Future的对象,在该对象上调用get()就能够获取到Callable任务返回的结果了。

注意:Future的get方法是阻塞的,即:线程无返回结果,get方法会一直等待。

CreateThreadDemo4.java

java 复制代码
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CreateThreadDemo4 {
    
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("---- 主程序开始运行 ----");
        Date startTime = new Date();
        
        int taskSize = 5;
        // 建立一个线程池,Executors提供了建立各类类型线程池的方法,具体详情请自行查阅
        ExecutorService executorService = Executors.newFixedThreadPool(taskSize);
        
        // 建立多个有返回值的任务
        List<Future> futureList = new ArrayList<Future>();
        for (int i = 0; i < taskSize; i++) {
            Callable callable = new MyCallable(i);
            // 执行任务并获取Future对象
            Future future = executorService.submit(callable);
            futureList.add(future);
        }
        
        // 关闭线程池
        executorService.shutdown();

        // 获取全部并发任务的运行结果
        for (Future future : futureList) {
            // 从Future对象上获取任务的返回值,并输出到控制台
            System.out.println(">>> " + future.get().toString());
        }

        Date endTime = new Date();
        System.out.println("---- 主程序结束运行 ----,程序运行耗时【" + (endTime.getTime() - startTime.getTime()) + "毫秒】");
    }
}

class MyCallable implements Callable<Object> {
    private int taskNum;

    MyCallable(int taskNum) {
        this.taskNum = taskNum;
    }

    public Object call() throws Exception {
        System.out.println(">>> " + taskNum + " 线程任务启动");
        Date startTime = new Date();
        Thread.sleep(1000);
        Date endTime = new Date();
        long time = endTime.getTime() - startTime.getTime();
        System.out.println(">>> " + taskNum + " 线程任务终止");
        return taskNum + "线程任务返回运行结果, 当前任务耗时【" + time + "毫秒】";
    }
}

五、其余建立线程的方式

固然,除了以上四种主要的线程建立方式以外,也还有不少其余的方式能够启动多线程任务。好比经过Timer启动定时任务,或者经过像Spring Task和quartz这样的第三方任务调度框架也能够开启多线程任务,关于第三方任务调度框架的例子还请查询相关资料。

相关推荐
隔窗听雨眠9 分钟前
ORM框架选型指南:MyBatis与Hibernate的全面对比
java·开发语言·数据库
ZHW_AI课题组9 分钟前
使用Stable Diffusion v1.5文本引导与无分类器引导(CFG)算法实现条件生成图片
人工智能·python·算法·机器学习·stable diffusion
盼小辉丶10 分钟前
OpenCV-Python实战(25)——基于深度传感器与凸性分析打造实时手势识别系统
人工智能·python·opencv·计算机视觉
-凌凌漆-12 分钟前
【Qt】C++中protected与private的区别
开发语言·c++·qt
金融大 k15 分钟前
行情数据接入 MCP:Claude Code / Cursor 工具描述怎么写才不踩坑
人工智能·python·websocket·行情 api
j7~16 分钟前
【C++】类和对象(上)--带你全面理解类和对象的概念,以及this指针的理解和相关面试题
java·开发语言·封装·this指针·类的实例化·访问限定符·类的命名
叶帆16 分钟前
【YFIOs】用C#开发硬件之串口通信
开发语言·c#
于先生吖17 分钟前
同城物流创业项目,Java源码搭建多车型搬家拉货、就近配货预约小程序
java·开发语言·小程序
码不停蹄的玄黓18 分钟前
Java 异常分类
java·开发语言
牛油果子哥q22 分钟前
【C++前置声明与头文件】C++前置声明与头文件深度精讲:重复包含、循环依赖、重复定义报错、工程编译架构与实战解决方案
开发语言·c++