线程 是一个轻量级的进程,它允许程序通过并行运行多个线程而更有效地运行。在这个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()
Thread的start() 方法被认为是多线程的核心。不执行这个方法,我们就不能启动一个新的线程。除了虚拟线程之外,其他方法在内部也使用这个方法来启动线程。
*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();
最终,Thread 类
start()方法是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的 一个扩展 。它实现了Future和CompletionStage* 接口。它提供了创建、连锁和组合多个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甚至是虚拟线程的方法。
祝你学习愉快!!