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();
            }
        }
    }
相关推荐
码上一元1 小时前
SpringBoot自动装配原理解析
java·spring boot·后端
计算机-秋大田1 小时前
基于微信小程序的养老院管理系统的设计与实现,LW+源码+讲解
java·spring boot·微信小程序·小程序·vue
魔道不误砍柴功3 小时前
简单叙述 Spring Boot 启动过程
java·数据库·spring boot
失落的香蕉3 小时前
C语言串讲-2之指针和结构体
java·c语言·开发语言
枫叶_v3 小时前
【SpringBoot】22 Txt、Csv文件的读取和写入
java·spring boot·后端
wclass-zhengge3 小时前
SpringCloud篇(配置中心 - Nacos)
java·spring·spring cloud
路在脚下@3 小时前
Springboot 的Servlet Web 应用、响应式 Web 应用(Reactive)以及非 Web 应用(None)的特点和适用场景
java·spring boot·servlet
黑马师兄3 小时前
SpringBoot
java·spring
数据小小爬虫4 小时前
如何用Java爬虫“偷窥”淘宝商品类目API的返回值
java·爬虫·php
暮春二十四4 小时前
关于用postman调用接口成功但是使用Java代码调用却失败的问题
java·测试工具·postman