Java 中创建线程几种方式

目录

概述

[一. 继承Thread类](#一. 继承Thread类)

[1. 特点](#1. 特点)

[2. 注意事项](#2. 注意事项)

[3. 代码示例](#3. 代码示例)

[二. 实现Runnable接口](#二. 实现Runnable接口)

[1. 特点](#1. 特点)

[2. 注意事项](#2. 注意事项)

[3. 代码示例](#3. 代码示例)

[三. 实现Callable接口](#三. 实现Callable接口)

[1. 特点](#1. 特点)

[2. 注意事项](#2. 注意事项)

[3. 代码示例](#3. 代码示例)


概述

在Java中,线程(Thread)是程序执行的最小单元,它允许程序在同一时间执行多个任务。Java中的线程可以由Thread类创建,也可以通过实现Runnable接口或Callable接口创建。

java中线程几种状态:

  1. 新建(New) : 线程对象已经被创建,但还没有调用start()方法。

  2. 可运行(Runnable) : 线程已经调用了start()方法,但还没有获得CPU时间片执行。可运行状态包括了操作系统线程的就绪(Ready)和运行(Running)状态。

  3. 阻塞(Blocked): 线程因为等待监视器锁而被阻塞,无法继续执行。

  4. 等待(Waiting) : 线程通过调用wait()join()LockSupport.park()等方法进入等待状态,需要其他线程通知或中断后才可能继续执行。

  5. 超时等待(Timed Waiting) : 线程通过调用带有超时参数的sleep()wait()join()LockSupport.parkNanos()LockSupport.parkUntil()等方法进入超时等待状态,超时后会自动唤醒。

  6. 终止(Terminated) : 线程的run()方法执行结束,或者因异常退出了run()方法。

线程的状态枚举类 State

一. 继承Thread类

通过继承Thread类并重写run方法来创建线程,本质上继承Thread类实现线程的方式也是通过实现 Runnable 接口,

1. 特点

  • 简单性:实现线程的代码简单直观。
  • 局限性 :由于Java的单继承特性,如果一个类已经继承了其他类,就不能再继承Thread类。

2. 注意事项

  • 不要调用Thread类的run方法 :应该重写run方法,而不是直接调用它。
  • 使用start方法启动线程start方法会创建一个新的线程,并调用run方法。
  • 线程安全:如果线程之间需要共享数据,需要考虑线程安全问题。

3. 代码示例

java 复制代码
package com.demo.thread;

/**
 * 文件名:ThreadDemo
 * 创建者:
 * 创建时间:2024-09-22
 * 描述: 通过继承 Thread 类并重写run方法来创建线程
 */
public class ThreadDemo extends Thread{
    @Override
    public void run(){
        System.out.println(Thread.currentThread().getName()+"-执行run方法");
    }
}

/**
 * 测试类
 */
class MainThread{
    public static void main(String[] args) {
        //1.第一种方式创建线程
        Thread thread = new Thread(new ThreadDemo(),"线程1");
        thread.start(); //启动线程

        //2.第二种方式创建线程
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"-执行run方法");
            }
        },"线程2");
        thread2.start(); //启动线程
    }
}

二. 实现Runnable接口

实现 Runnable 接口是Java中创建线程的另一种常见方式,这种方式更加灵活,因为它允许类继承其他类的同时实现线程功能。Runnable 接口定义了一个 run 方法,这是线程执行的入口点。

1. 特点

  • 灵活性 :实现 Runnable 接口允许类继承其他类,同时实现多线程功能。
  • 线程安全 :如果多个线程共享同一个 Runnable 实例,需要考虑线程安全问题。

2. 注意事项

  • 不要在 run 方法中调用 Thread.currentThread().stop():这是不推荐的做法,因为它可能会导致程序处于不确定状态。
  • 异常处理 :在 run 方法中妥善处理异常,避免线程意外终止。
  • 资源清理:如果线程使用了一些资源(如文件句柄、数据库连接等),确保在线程结束时释放这些资源。

3. 代码示例

java 复制代码
package com.demo.thread;

/**
 * 文件名:RunnableDemo
 * 创建者:
 * 创建时间:2024-09-22
 * 描述:实现 Runnable接口创建线程
 */
public class RunnableDemo implements Runnable{
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-"+"执行run方法");
    }
}

/**
 * 测试类
 */
class MainDemo{
    public static void main(String[] args) {
        //1.第一种创建线程执行
        Thread thread = new Thread(new RunnableDemo(),"线程1");
        thread.start(); // 启动线程

        //2.第二种创建线程执行
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"-执行run方法");
            }
        },"线程2");
        thread2.start(); // 启动线程

    }
}

三. 实现Callable接口

当我们需要创建一个可以返回结果的线程时,就可以使用实现了Callable接口的方式。Callable接口是在Java 5中引入的,它允许线程执行一个任务并返回一个结果,与Runnable接口相比,Callable接口的call()方法可以返回结果并抛出异常。

Callable 接口与 Runnable 接口类似,但它可以返回一个结果并且能抛出异常。Callable 通常与 FutureTask 一起使用,后者实现了 Runnable 接口,并且包装了 Callable 对象。

1. 特点

  • 返回结果Callable 任务可以返回一个结果,可以通过 FutureTask.get() 方法获取。
  • 抛出异常Callable 任务可以抛出异常,可以通过 FutureTask.get() 方法捕获。

2. 注意事项

  • 异常处理 :在 call 方法中抛出的异常可以通过 FutureTask.get() 方法的调用者捕获。
  • 线程安全 :如果 Callable 任务需要访问共享资源,需要考虑线程安全问题。

3. 代码示例

使用步骤:

  1. 创建一个实现 Callable 接口的类
  2. 实现 Callable 接口的 call 方法,该方法是线程执行的入口点。
  3. 创建 Callable 实例
  4. Callable 实例传递给 FutureTask 的构造器
  5. FutureTask 对象传递给 Thread 类的构造器
  6. 创建 Thread 对象
  7. 调用 Thread 对象的 start 方法来启动线程。
  1. 简单使用

    java 复制代码
    package com.demo.thread;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    /**
     * 文件名:CallableDemo
     * 创建者:
     * 创建时间:2024-09-22
     * 描述:通过 Callable 接口实现线程创建
     */
    public class CallableDemo implements Callable<String> {
        @Override
        public String call() throws Exception {
            return "测试";
        }
    }
    
    /**
     * 测试类
     */
    class MainCallable{
        public static void main(String[] args){
            //1.创建对象
            CallableDemo demo = new CallableDemo();
            FutureTask<String> futureTask = new FutureTask<>(demo);
            //2.创建线程
            Thread thread = new Thread(futureTask);
            thread.start();
            //3.获取返回结果
            String res;
            try {
                res = futureTask.get();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (ExecutionException e) {
                throw new RuntimeException(e);
            }
            System.out.println("获取线程返回结果:"+res);
        }
    }
  2. 通过线程池使用

    java 复制代码
    package com.demo.thread;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    /**
     * 文件名:Main
     * 创建者:
     * 创建时间:2024-09-22
     * 描述:
     */
    public class Main {
        public static void main(String[] args) {
            //1.创建一个线程池
            ExecutorService executorService = Executors.newSingleThreadExecutor();
            //2.创建Callable任务
            Callable<String> callableTask = () -> {
                Thread.sleep(2000); // 模拟长时间运行的任务
                return "测试";
            };
            //3.提交Callable任务并获取Future对象
            Future<String> future = executorService.submit(callableTask);
            try {
                //3.获取异步任务的执行结果
                String result = future.get(); //此方法会阻塞,直到任务执行完成
                System.out.println("任务执行结果: " + result);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //4.关闭线程池
                executorService.shutdown();
            }
        }
    }
相关推荐
躺平大鹅2 小时前
Java面向对象入门(类与对象,新手秒懂)
java
初次攀爬者2 小时前
RocketMQ在Spring Boot上的基础使用
java·spring boot·rocketmq
花花无缺2 小时前
搞懂@Autowired 与@Resuorce
java·spring boot·后端
Derek_Smart4 小时前
从一次 OOM 事故说起:打造生产级的 JVM 健康检查组件
java·jvm·spring boot
NE_STOP5 小时前
MyBatis-mybatis入门与增删改查
java
孟陬8 小时前
国外技术周刊 #1:Paul Graham 重新分享最受欢迎的文章《创作者的品味》、本周被划线最多 YouTube《如何在 19 分钟内学会 AI》、为何我不
java·前端·后端
想用offer打牌8 小时前
一站式了解四种限流算法
java·后端·go
华仔啊9 小时前
Java 开发千万别给布尔变量加 is 前缀!很容易背锅
java
也些宝9 小时前
Java单例模式:饿汉、懒汉、DCL三种实现及最佳实践
java