8种创建Java线程的方式,你知道几个?

简介: 8种创建Java线程的方式

作者:唐彤

简介

创建线程,是多线程编程中最基本的操作,彤哥总结了一下,大概有8种创建线程的方式,你知道吗?
image

1.继承Thread类并重写run()方法

public class CreatingThread01 extends Thread {
 @Override
 public void run() {
 System.out.println(getName() + " is running");
 }
 public static void main(String[] args) {
 new CreatingThread01().start();
 new CreatingThread01().start();
 new CreatingThread01().start();
 new CreatingThread01().start();
 }
}

继承Thread类并重写run()方法,这种方式的弊端是一个类只能继承一个父类,如果这个类本身已经继承了其它类,就不能使用这种方式了。

2.实现Runnable接口

public class CreatingThread02 implements Runnable {
 @Override
 public void run() {
 System.out.println(Thread.currentThread().getName() + " is running");
 }
 public static void main(String[] args) {
 new Thread(new CreatingThread02()).start();
 new Thread(new CreatingThread02()).start();
 new Thread(new CreatingThread02()).start();
 new Thread(new CreatingThread02()).start();
 }
}

实现Runnable接口,这种方式的好处是一个类可以实现多个接口,不影响其继承体系。

3.匿名内部类

public class CreatingThread03 {
 public static void main(String[] args) {
 // Thread匿名类,重写Thread的run()方法
 new Thread() {
 @Override
 public void run() {
 System.out.println(getName() + " is running");
 }
 }.start();
 // Runnable匿名类,实现其run()方法
 new Thread(new Runnable() {
 @Override
 public void run() {
 System.out.println(Thread.currentThread().getName() + " is running");
 }
 }).start();
 // 同上,使用lambda表达式函数式编程
 new Thread(()->{
 System.out.println(Thread.currentThread().getName() + " is running");
 }).start();
 }
}

使用匿名类的方式,一是重写Thread的run()方法,二是传入Runnable的匿名类,三是使用lambda方式,现在一般使用第三种(java8+),简单快捷。

4.实现Callabe接口

public class CreatingThread04 implements Callable<Long> {
 @Override
 public Long call() throws Exception {
 Thread.sleep(2000);
 System.out.println(Thread.currentThread().getId() + " is running");
 return Thread.currentThread().getId();
 }
 public static void main(String[] args) throws ExecutionException, InterruptedException {
 FutureTask<Long> task = new FutureTask<>(new CreatingThread04());
 new Thread(task).start();
 System.out.println("等待完成任务");
 Long result = task.get();
 System.out.println("任务结果:" + result);
 }
}

实现Callabe接口,可以获取线程执行的结果,FutureTask实际上实现了Runnable接口。
image

5.定时器(java.util.Timer)

public class CreatingThread05 {
 public static void main(String[] args) {
 Timer timer = new Timer();
 // 每隔1秒执行一次
        timer.schedule(new TimerTask() {
 @Override
 public void run() {
 System.out.println(Thread.currentThread().getName() + " is running");
 }
 }, 0 , 1000);
 }
}

使用定时器java.util.Timer可以快速地实现定时任务,TimerTask实际上实现了Runnable接口。

6.线程池

public class CreatingThread06 {
 public static void main(String[] args) {
 ExecutorService threadPool = Executors.newFixedThreadPool(5);
 for (int i = 0; i < 100; i++) {
            threadPool.execute(()-> System.out.println(Thread.currentThread().getName() + " is running"));
 }
 }
}

使用线程池的方式,可以复用线程,节约系统资源。

7.并行计算(Java8+)

public class CreatingThread07 {
 public static void main(String[] args) {
 List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
 // 串行,打印结果为12345
        list.stream().forEach(System.out::print);
 System.out.println();
 // 并行,打印结果随机,比如35214
        list.parallelStream().forEach(System.out::print);
 }
}

使用并行计算的方式,可以提高程序运行的效率,多线程并行执行。

8.Spring异步方法

首先,springboot启动类加上 @EnableAsync注解(@EnableAsync是spring支持的,这里方便举例使用springboot)。

@SpringBootApplication
@EnableAsync
public class Application {
 public static void main(String[] args) {
 SpringApplication.run(Application.class, args);
 }
}

其次,方法加上 @Async注解。

@Service
public class CreatingThread08Service {
 @Async
 public void call() {
 System.out.println(Thread.currentThread().getName() + " is running");
 }
}

然后,测试用例直接跟使用一般的Service方法一模一样。

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class CreatingThread08Test {
 @Autowired
 private CreatingThread08Service creatingThread08Service;
 @Test
 public void test() {
        creatingThread08Service.call();
        creatingThread08Service.call();
        creatingThread08Service.call();
        creatingThread08Service.call();
 }
}

运行结果如下:

task-3 is running
task-2 is running
task-1 is running
task-4 is running

可以看到每次执行方法时使用的线程都不一样。
使用Spring异步方法的方式,可以说是相当地方便,适用于前后逻辑不相关联的适合用异步调用的一些方法,比如发送短信的功能。
欢迎大家关注我的公种浩【程序员追风】,文章都会在里面更新,整理的资料也会放在里面。

总结

(1)继承Thread类并重写run()方法;
(2)实现Runnable接口;
(3)匿名内部类;
(4)实现Callabe接口;
(5)定时器(java.util.Timer);
(6)线程池;
(7)并行计算(Java8+);
(8)Spring异步方法;
image

福利

上面介绍了那么多创建线程的方式,其实本质上就两种,一种是继承Thread类并重写其run()方法,一种是实现Runnable接口的run()方法,那么它们之间到底有什么联系呢?
请看下面的例子,同时继承Thread并实现Runnable接口,应该输出什么呢?

public class CreatingThread09 {
 public static void main(String[] args) {
 new Thread(()-> {
 System.out.println("Runnable: " + Thread.currentThread().getName());
 }) {
 @Override
 public void run() {
 System.out.println("Thread: " + getName());
 }
 }.start();
 }
}

说到这里,我们有必要看一下Thread类的源码:

public class Thread implements Runnable {
 // Thread维护了一个Runnable的实例
 private Runnable target;
 public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
 }
 public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
 }
 private void init(ThreadGroup g, Runnable target, String name,
 long stackSize, AccessControlContext acc,
 boolean inheritThreadLocals) {
 // ...
 // 构造方法传进来的Runnable会赋值给target
 this.target = target;
 // ...
 }
 @Override
 public void run() {
 // Thread默认的run()方法,如果target不为空,会执行target的run()方法
 if (target != null) {
            target.run();
 }
 }
}

看到这里是不是豁然开朗呢?既然上面的例子同时继承Thread并实现了Runnable接口,根据源码,实际上相当于重写了Thread的run()方法,在Thread的run()方法时实际上跟target都没有关系了。
所以,上面的例子输出结果为 Thread:Thread-0,只输出重写Thread的run()方法中的内容。

最后

欢迎大家一起交流,喜欢文章记得点个赞哟,感谢支持!

相关文章
|
8天前
|
存储 Java 数据库连接
java多线程之线程通信
java多线程之线程通信
|
9天前
|
安全 Java 开发者
深入理解Java并发编程:线程安全与性能优化
【4月更文挑战第9天】本文将深入探讨Java并发编程的核心概念,包括线程安全和性能优化。我们将详细解析Java中的同步机制,包括synchronized关键字、Lock接口以及并发集合等,并探讨它们如何影响程序的性能。此外,我们还将讨论Java内存模型,以及它如何影响并发程序的行为。最后,我们将提供一些实用的并发编程技巧和最佳实践,帮助开发者编写出既线程安全又高效的Java程序。
22 3
|
12天前
|
Java 调度
Java并发编程:深入理解线程池的原理与实践
【4月更文挑战第6天】本文将深入探讨Java并发编程中的重要概念——线程池。我们将从线程池的基本原理入手,逐步解析其工作过程,以及如何在实际开发中合理使用线程池以提高程序性能。同时,我们还将关注线程池的一些高级特性,如自定义线程工厂、拒绝策略等,以帮助读者更好地掌握线程池的使用技巧。
|
12天前
|
设计模式 安全 Java
Java并发编程实战:使用synchronized关键字实现线程安全
【4月更文挑战第6天】Java中的`synchronized`关键字用于处理多线程并发,确保共享资源的线程安全。它可以修饰方法或代码块,实现互斥访问。当用于方法时,锁定对象实例或类对象;用于代码块时,锁定指定对象。过度使用可能导致性能问题,应注意避免锁持有时间过长、死锁,并考虑使用`java.util.concurrent`包中的高级工具。正确理解和使用`synchronized`是编写线程安全程序的关键。
|
10天前
|
Java
Java 并发编程:深入理解线程池
【4月更文挑战第8天】本文将深入探讨 Java 中的线程池技术,包括其工作原理、优势以及如何使用。线程池是 Java 并发编程的重要工具,它可以有效地管理和控制线程的执行,提高系统性能。通过本文的学习,读者将对线程池有更深入的理解,并能在实际开发中灵活运用。
|
13天前
|
Java 程序员 调度
Java中的多线程编程:基础知识与实践
【4月更文挑战第5天】 在现代软件开发中,多线程编程是一个不可或缺的技术要素。它允许程序员编写能够并行处理多个任务的程序,从而充分利用多核处理器的计算能力,提高应用程序的性能。Java作为一种广泛使用的编程语言,提供了丰富的多线程编程支持。本文将介绍Java多线程编程的基础知识,并通过实例演示如何创建和管理线程,以及如何解决多线程环境中的常见问题。
|
8天前
|
算法 Java 开发者
Java中的多线程编程:概念、实现与性能优化
【4月更文挑战第9天】在Java编程中,多线程是一种强大的工具,它允许开发者创建并发执行的程序,提高系统的响应性和吞吐量。本文将深入探讨Java多线程的核心概念,包括线程的生命周期、线程同步机制以及线程池的使用。接着,我们将展示如何通过继承Thread类和实现Runnable接口来创建线程,并讨论各自的优缺点。此外,文章还将介绍高级主题,如死锁的预防、避免和检测,以及如何使用并发集合和原子变量来提高多线程程序的性能和安全性。最后,我们将提供一些实用的性能优化技巧,帮助开发者编写出更高效、更稳定的多线程应用程序。
|
6天前
|
安全 算法 Java
深入理解Java并发编程:线程安全与性能优化
【4月更文挑战第11天】 在Java中,高效的并发编程是提升应用性能和响应能力的关键。本文将探讨Java并发的核心概念,包括线程安全、锁机制、线程池以及并发集合等,同时提供实用的编程技巧和最佳实践,帮助开发者在保证线程安全的前提下,优化程序性能。我们将通过分析常见的并发问题,如竞态条件、死锁,以及如何利用现代Java并发工具来避免这些问题,从而构建更加健壮和高效的多线程应用程序。
|
11天前
|
Java
Java并发编程:深入理解线程池
【4月更文挑战第7天】在现代软件开发中,多线程编程已经成为一种不可或缺的技术。为了提高程序性能和资源利用率,Java提供了线程池这一强大工具。本文将深入探讨Java线程池的原理、使用方法以及如何根据实际需求定制线程池,帮助读者更好地理解和应用线程池技术。
15 0
|
2天前
|
设计模式 运维 安全
深入理解Java并发编程:线程安全与性能优化
【4月更文挑战第15天】在Java开发中,多线程编程是提升应用程序性能和响应能力的关键手段。然而,它伴随着诸多挑战,尤其是在保证线程安全的同时如何避免性能瓶颈。本文将探讨Java并发编程的核心概念,包括同步机制、锁优化、线程池使用以及并发集合等,旨在为开发者提供实用的线程安全策略和性能优化技巧。通过实例分析和最佳实践的分享,我们的目标是帮助读者构建既高效又可靠的多线程应用。