如何在Java中创建和启动一个新线程

109 阅读4分钟

线程 是一个轻量级的进程,它允许程序通过并行运行多个线程而更有效地运行。在这个Java并发性教程中,我们将学习以不同的方式创建和执行线程以及它们的使用情况。

1.创建一个新的线程

在Java中,我们可以通过以下方式创建一个线程

  • 通过扩展线程
  • 通过实现Runnable 接口
  • 使用Lambda表达式

1.1.通过扩展线程

要创建一个新的线程,请用Thread扩展该类,并重写run() 方法。

class SubTask extends Thread {
  public void run() {
    System.out.println("SubTask started...");
  }
}

1.2.通过实现Runnable 接口

实现Runnable接口被认为是一种更好的方法,因为通过这种方式,线程类可以扩展任何其他类。记住,在Java中,一个类只能扩展一个类,但实现多个接口。

class SubTaskWithRunnable implements Runnable {

1.3.使用Lambda表达式

兰姆达表达式有助于创建功能接口的内联实例,可以帮助减少模板代码。

Runnable subTaskWithLambda = () ->
{
  System.out.println("SubTaskWithLambda started...");
};

2.启动一个新的线程

我们可以通过多种方式在Java中启动一个新线程,让我们来了解一下。

2.1.使用Thread.start()

Threadstart() 方法被认为是多线程的核心。不执行这个方法,我们就不能启动一个新的线程。除了虚拟线程之外,其他方法在内部也使用这个方法来启动线程。

*start()*方法负责向平台的线程调度器注册线程,并进行所有其他强制性活动,如资源分配。

让我们通过一个例子来学习如何使用start()方法来创建和启动一个线程

class SubTask extends Thread {
  public void run() {
    System.out.println("SubTask started...");
  }
}

Thread subTask = new SubTask();
subTask.start();

我们可以使用start()方法来执行用Runnable接口创建的线程。

class SubTaskWithRunnable implements Runnable {
  public void run() {
    System.out.println("SubTaskWithRunnable started...");
  }
}

Thread subTaskWithRunnable = new Thread(new SubTaskWithRunnable());
subTaskWithRunnable.start();

使用lambda表达式技术与Runnable接口方法没有区别。

Runnable subTaskWithLambda = () -> {
  System.out.println("SubTaskWithLambda started...");
};

Thread subTask = new Thread(subTaskWithLambda);
subTask.start();

最终,Threadstart()方法是Java中启动一个新线程的唯一方法 。其他方式(除了virtaul线程)内部使用start()方法。

2.2.使用ExecutorService

创建一个新的线程 是需要资源的。因此,为每个子任务创建一个新的线程,会降低应用程序的性能。为了克服这些问题,我们应该使用线程池

线程池是 一个已经创建好的 线程可以随时完成我们的任务。在Java中,ExecutorService是创建和管理线程池的骨干。我们可以提交一个 可运行的可调用任务,然后它就会使用线程池中的一个线程来执行所提交的任务。

Runnable subTaskWithLambda = () -> {
  System.out.println("SubTaskWithLambda started...");
};

ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(subTaskWithLambda);

如果我们使用lambda表达式来创建线程,那么整个语法就变得非常简单。

ExecutorService executorService = Executors.newFixedThreadPool(10);

executorService.execute(() ->
{
  System.out.println("SubTaskWithLambda started...");
});

2.3.使用ScheduledExecutorService进行延迟执行

当我们提交一个任务给执行器时,它会尽快执行。但是如果我们想在一定时间后执行任务,或者定期运行任务,那么我们可以使用 ScheduledExecutorService。

下面的例子是调度一个任务在延迟1o秒后执行,当它完成执行后将返回结果 "完成"。

ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);

ScheduledFuture<String> result = executor.schedule(() -> {
	System.out.println("Thread is executing the job");
	return "completed";
}, 10, TimeUnit.SECONDS);

System.out.println(result.get());

2.4.使用CompletableFuture

CompletableFuture 是在Java 8中引入的 Future API的 一个扩展 。它实现了FutureCompletionStage* 接口。它提供了创建、连锁和组合多个Future的方法。

在下面的例子中,CompletableFuture 将启动一个新的线程,并通过在该线程上使用runAsync()supplyAsync()方法执行所提供的任务。

// Running RunnableJob using runAsync() method of CompletableFuture
CompletableFuture<Void> future = CompletableFuture.runAsync(new RunnableJob());

// Running a task using supplyAsync() method of CompletableFuture and return the result
CompletableFuture<String> result = CompletableFuture.supplyAsync(() -> "Thread is executing");

// Getting result from CompletableFuture
System.out.println(result.get());

2.5.作为一个虚拟线程执行

自Java 19以来,虚拟线程被添加为JVM管理的轻量级线程,这将有助于编写高吞吐量的并发应用程序

我们可以使用新增加的API将一个任务作为虚拟线程运行。

Runnable runnable = () -> System.out.println("Inside Runnable");
Thread.startVirtualThread(runnable);

//or

Thread.startVirtualThread(() -> {
	//Code to execute in virtual thread
	System.out.println("Inside Runnable");
});

//or

Thread.Builder builder = Thread.ofVirtual().name("Virtual-Thread");
builder.start(runnable); 

3.总结

我们已经学会了在java中创建和启动一个新线程不同方法。我们学习了创建线程类、Runnable接口、ExecutorService甚至是虚拟线程的方法。

祝你学习愉快!!