欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 能源 > 线程的多种创建方式和使用

线程的多种创建方式和使用

2025/2/22 2:23:40 来源:https://blog.csdn.net/m0_72560900/article/details/145716913  浏览:    关键词:线程的多种创建方式和使用

一、线程的多种创建方式

在 Java 中,创建线程有多种方式,每种方式都有其特定的应用场景。以下是 Java 中常用的几种创建线程的方式,以及它们的具体实现:

1、通过继承 Thread 类创建线程

Java 中的 Thread 类提供了一个可执行的线程对象。通过继承 Thread 类并重写其 run() 方法来定义线程的执行体。

示例代码1:
class MyThread extends Thread {@Overridepublic void run() {// 线程要执行的代码System.out.println("Thread is running");}
}public class ThreadExample {public static void main(String[] args) {MyThread thread = new MyThread(); // 创建线程对象thread.start(); // 启动线程}
}
示例代码2:使用匿名内部类
public class AnonymousThreadExample {public static void main(String[] args) {// 创建线程并通过匿名内部类继承 Thread 类Thread thread = new Thread() {@Overridepublic void run() {// 线程要执行的代码System.out.println("Thread is running using Anonymous Thread");}};thread.start();  // 启动线程}
}
说明:
  • 优点:简单直接,适用于简单的线程创建。
  • 缺点:Java 中类只能继承一个类,因此如果已经继承了其他类,不能再继承 Thread 类。

2、通过实现 Runnable 接口创建线程

实现 Runnable 接口是一种更加灵活的方式,它可以避免 Java 单继承的限制。通过实现 Runnable 接口的 run() 方法来定义线程的执行体,再通过 Thread 类来启动该线程。

示例代码:
class MyRunnable implements Runnable {@Overridepublic void run() {// 线程要执行的代码System.out.println("Thread is running");}
}public class RunnableExample {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable(); // 创建 Runnable 实现类对象Thread thread = new Thread(myRunnable); // 将 Runnable 实现类传递给 Threadthread.start(); // 启动线程}
}
说明:
  • 优点:比继承 Thread 更灵活,可以同时继承其他类。适用于多线程共享同一资源的情况。
  • 缺点:需要通过 Thread 对象来启动线程,不能直接调用 start() 方法。

3、通过实现 Callable 接口创建线程(可返回值)

Callable 接口与 Runnable 类似,但它允许任务执行时返回结果,可以处理异常。通常与 ExecutorService 配合使用,能够提交任务并获得执行结果。

示例代码:
import java.util.concurrent.*;class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {// 线程要执行的代码return "Thread is running and returning result";}
}public class CallableExample {public static void main(String[] args) throws ExecutionException, InterruptedException {MyCallable myCallable = new MyCallable();ExecutorService executorService = Executors.newCachedThreadPool(); // 创建线程池Future<String> future = executorService.submit(myCallable); // 提交任务String result = future.get(); // 获取任务的执行结果System.out.println(result); // 输出结果executorService.shutdown(); // 关闭线程池}
}
说明:
  • 优点:能够返回任务执行结果,适用于需要计算并返回结果的场景。
  • 缺点:需要使用 ExecutorService 来执行任务,相比 Runnable 略显复杂。

4、通过 ExecutorService 创建线程池

线程池是一种管理线程的方式,通过 ExecutorService 可以创建线程池并提交任务,线程池会自动管理线程的创建、销毁和复用。通过线程池可以有效地管理多线程任务,避免频繁的线程创建销毁操作。

示例代码:
import java.util.concurrent.*;class MyTask implements Runnable {@Overridepublic void run() {System.out.println("Thread is running from ExecutorService");}
}public class ExecutorServiceExample {public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(3); // 创建固定大小的线程池for (int i = 0; i < 5; i++) {executorService.submit(new MyTask()); // 提交任务给线程池}executorService.shutdown(); // 关闭线程池}
}
说明:
  • 优点:可以管理大量线程,自动复用线程,提高性能。适用于高并发的场景。
  • 缺点:需要额外的线程池管理,使用稍微复杂。

5、通过 ForkJoinPool 创建线程(适用于分治任务)

ForkJoinPool 是一种专门用于处理大规模并行任务的线程池,特别适合分治型任务的执行。它通过将任务分割为多个子任务并行执行来提高性能。

示例代码:
import java.util.concurrent.*;class MyForkJoinTask extends RecursiveTask<Integer> {@Overrideprotected Integer compute() {// 线程要执行的代码return 1; // 示例返回值}
}public class ForkJoinPoolExample {public static void main(String[] args) {ForkJoinPool forkJoinPool = new ForkJoinPool(); // 创建 ForkJoinPoolMyForkJoinTask task = new MyForkJoinTask();ForkJoinTask<Integer> result = forkJoinPool.submit(task); // 提交任务System.out.println("Result: " + result.join()); // 获取结果forkJoinPool.shutdown(); // 关闭线程池}
}
说明:
  • 优点:适合计算密集型任务和分治型任务,能够有效处理大量子任务。
  • 缺点:相对于其他线程池,使用场景更为特殊。

6、通过 Lambda 表达式创建线程(简化代码)

Java 8 引入了 Lambda 表达式,可以简化线程的创建过程。通常与 Runnable 接口配合使用,能够在一行代码中定义线程的执行内容。

示例代码:
public class LambdaThreadExample {public static void main(String[] args) {// 使用 Lambda 表达式创建线程Thread thread = new Thread(() -> {System.out.println("Thread is running using Lambda");});thread.start(); // 启动线程}
}
说明:
  • 优点:代码简洁,减少了冗长的类定义,适用于快速创建简单线程。
  • 缺点:仅适用于 Runnable 接口场景,对于其他接口无法使用。

7、总结

Java 提供了多种方式来创建线程,每种方式都有其特定的优势和适用场景:

  1. 继承 Thread 类:适合简单的线程创建,但不能继承其他类。
  2. 实现 Runnable 接口:适合多线程共享资源的情况,比继承 Thread 更灵活。
  3. 实现 Callable 接口:适合需要返回结果的线程任务,通常与 ExecutorService 配合使用。
  4. 使用 ExecutorService:适合管理大量线程,自动复用线程,提高系统性能。
  5. 使用 ForkJoinPool:适合大规模并行计算和分治型任务。
  6. 使用 Lambda 表达式:适合快速创建简单线程,代码简洁。

选择哪种方式,取决于具体应用场景和任务需求。在实际开发中,通常推荐使用 ExecutorServiceForkJoinPool 来管理线程,以提高代码的可维护性和性能。

二、Thread类最常用个方法

1. start()

功能:启动一个新线程,使其进入就绪状态,等待操作系统调度执行。

  • 作用:启动线程后,JVM 会自动调用 run() 方法,并在新的线程中执行。
  • 注意:线程一旦启动后,不能再次启动。如果调用 start() 方法多次,会抛出 IllegalThreadStateException 异常。
Thread thread = new Thread(() -> System.out.println("Thread is running"));
thread.start();  // 启动线程

2. run()

功能:线程的执行体方法,定义线程启动后要执行的代码。

  • 作用:当调用 start() 启动线程时,JVM 会调用 run() 方法。通常情况下,run() 方法会被覆盖,定义线程的具体执行逻辑。
  • 注意:直接调用 run() 方法只是将 run() 方法作为普通方法调用,并不会启动新的线程,仍然是在主线程中执行。
@Override
public void run() {System.out.println("Thread is running");
}

3. sleep(long millis)

功能:让当前线程暂停指定时间(以毫秒为单位),进入 休眠状态,不会占用 CPU 资源。

  • 作用:使当前线程暂时进入休眠状态,休眠结束后,线程会回到就绪状态,等待操作系统调度。
  • 注意sleep() 方法是静态的,作用于调用它的当前线程,且可以抛出 InterruptedException 异常。
try {Thread.sleep(1000);  // 当前线程暂停 1000 毫秒(1秒)
} catch (InterruptedException e) {e.printStackTrace();
}

4. join()

功能:使当前线程等待目标线程完成后再继续执行,常用于 线程同步

  • 作用join() 方法会使当前线程等待调用它的线程(即目标线程)执行完毕后再继续执行。
  • 注意:可以指定等待时间,等待超时后 join() 方法会返回。
// 创建子线程对象
Thread thread = new Thread(() -> System.out.println("Thread is running"));
// 执行子线程
thread.start();
try {thread.join();  // 当前线程(即:主线程)等待子线程执行完
} catch (InterruptedException e) {e.printStackTrace();
}

5. interrupt()

功能:中断一个线程,设置线程的中断标志为 true,通知线程终止。

  • 作用:如果线程正在执行 sleep()wait()join() 等阻塞操作,interrupt() 会使这些操作抛出 InterruptedException,从而让线程终止或者退出阻塞。
  • 注意interrupt() 只是设置线程的中断标志,不会立即停止线程的执行。线程需要在合适的地方自行判断 Thread.interrupted() 或捕获 InterruptedException 来响应中断。
Thread thread = new Thread(() -> {try {Thread.sleep(5000);} catch (InterruptedException e) {System.out.println("Thread was interrupted");}
});
thread.start();
thread.interrupt();  // 中断线程

6. isAlive()

功能:判断线程是否已经启动并正在执行。

  • 作用:返回线程是否处于活动状态。如果线程处于 新建状态已死亡状态,返回 false;否则返回 true
Thread thread = new Thread(() -> System.out.println("Thread is running"));
thread.start();
System.out.println(thread.isAlive());  // true

7. getName()

功能:获取线程的名称。

  • 作用:返回当前线程的名字,通常是由 JVM 自动分配的,如 Thread-0Thread-1 等,也可以手动通过 setName() 方法来设置。
Thread thread = new Thread(() -> System.out.println(Thread.currentThread().getName()));
thread.start();  // 输出:Thread-0

8. setName(String name)

功能:设置线程的名称。

  • 作用:给当前线程指定一个名称。为线程设置名称有助于在调试和日志中跟踪线程。
Thread thread = new Thread(() -> System.out.println(Thread.currentThread().getName()));
thread.setName("CustomThread");
thread.start();  // 输出:CustomThread

9. getId()

功能:获取线程的唯一标识符。

  • 作用:返回当前线程的唯一 ID,通常用于调试和标识线程。
Thread thread = new Thread(() -> System.out.println(Thread.currentThread().getId()));
thread.start();  // 输出线程的 ID,例如:1

10. setPriority(int priority)

功能:设置线程的优先级,影响线程获取 CPU 时间片的频率。

  • 作用setPriority() 方法允许你设置线程的优先级(从 1 到 10,默认值为 5)。高优先级线程通常会更早地获得 CPU 时间片,但这也依赖于操作系统的线程调度策略。
Thread thread = new Thread(() -> System.out.println("Thread is running"));
thread.setPriority(Thread.MAX_PRIORITY);  // 设置为最高优先级
thread.start();

11. yield()

功能:使当前线程放弃 CPU 时间片,暂时让出 CPU 资源,允许其他线程执行。

  • 作用yield() 是一个静态方法,当前线程会让出 CPU 使用权,但是不会完全让出控制权,仍然可以继续执行。具体行为依赖于操作系统的线程调度策略。
Thread.yield();  // 当前线程暂停,让出 CPU 资源

12. currentThread()

功能:获取当前正在执行的线程对象。

  • 作用:返回代表当前正在执行线程的 Thread 对象。常用于获取当前线程的状态、名称等信息。
Thread current = Thread.currentThread();
System.out.println(current.getName());  // 输出当前线程的名称

三. 线程的生命周期

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词