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()方法中的内容。

最后

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

相关文章
|
14天前
|
存储 Java 数据库连接
java多线程之线程通信
java多线程之线程通信
|
14天前
|
算法 Java 开发者
Java中的多线程编程:概念、实现与性能优化
【4月更文挑战第9天】在Java编程中,多线程是一种强大的工具,它允许开发者创建并发执行的程序,提高系统的响应性和吞吐量。本文将深入探讨Java多线程的核心概念,包括线程的生命周期、线程同步机制以及线程池的使用。接着,我们将展示如何通过继承Thread类和实现Runnable接口来创建线程,并讨论各自的优缺点。此外,文章还将介绍高级主题,如死锁的预防、避免和检测,以及如何使用并发集合和原子变量来提高多线程程序的性能和安全性。最后,我们将提供一些实用的性能优化技巧,帮助开发者编写出更高效、更稳定的多线程应用程序。
|
12天前
|
安全 算法 Java
深入理解Java并发编程:线程安全与性能优化
【4月更文挑战第11天】 在Java中,高效的并发编程是提升应用性能和响应能力的关键。本文将探讨Java并发的核心概念,包括线程安全、锁机制、线程池以及并发集合等,同时提供实用的编程技巧和最佳实践,帮助开发者在保证线程安全的前提下,优化程序性能。我们将通过分析常见的并发问题,如竞态条件、死锁,以及如何利用现代Java并发工具来避免这些问题,从而构建更加健壮和高效的多线程应用程序。
|
4天前
|
安全 Java
深入理解 Java 多线程和并发工具类
【4月更文挑战第19天】本文探讨了Java多线程和并发工具类在实现高性能应用程序中的关键作用。通过继承`Thread`或实现`Runnable`创建线程,利用`Executors`管理线程池,以及使用`Semaphore`、`CountDownLatch`和`CyclicBarrier`进行线程同步。保证线程安全、实现线程协作和性能调优(如设置线程池大小、避免不必要同步)是重要环节。理解并恰当运用这些工具能提升程序效率和可靠性。
|
5天前
|
安全 Java
java多线程(一)(火车售票)
java多线程(一)(火车售票)
|
5天前
|
安全 Java 调度
Java并发编程:深入理解线程与锁
【4月更文挑战第18天】本文探讨了Java中的线程和锁机制,包括线程的创建(通过Thread类、Runnable接口或Callable/Future)及其生命周期。Java提供多种锁机制,如`synchronized`关键字、ReentrantLock和ReadWriteLock,以确保并发访问共享资源的安全。此外,文章还介绍了高级并发工具,如Semaphore(控制并发线程数)、CountDownLatch(线程间等待)和CyclicBarrier(同步多个线程)。掌握这些知识对于编写高效、正确的并发程序至关重要。
|
5天前
|
安全 Java 程序员
Java中的多线程并发编程实践
【4月更文挑战第18天】在现代软件开发中,为了提高程序性能和响应速度,经常需要利用多线程技术来实现并发执行。本文将深入探讨Java语言中的多线程机制,包括线程的创建、启动、同步以及线程池的使用等关键技术点。我们将通过具体代码实例,分析多线程编程的优势与挑战,并提出一系列优化策略来确保多线程环境下的程序稳定性和性能。
|
6天前
|
缓存 分布式计算 监控
Java并发编程:深入理解线程池
【4月更文挑战第17天】在Java并发编程中,线程池是一种非常重要的技术,它可以有效地管理和控制线程的执行,提高系统的性能和稳定性。本文将深入探讨Java线程池的工作原理,使用方法以及在实际开发中的应用场景,帮助读者更好地理解和使用Java线程池。
|
6天前
|
存储 安全 Java
Java中的容器,线程安全和线程不安全
Java中的容器,线程安全和线程不安全
15 1
|
6天前
|
Java 开发者
Java中多线程并发控制的实现与优化
【4月更文挑战第17天】 在现代软件开发中,多线程编程已成为提升应用性能和响应能力的关键手段。特别是在Java语言中,由于其平台无关性和强大的运行时环境,多线程技术的应用尤为广泛。本文将深入探讨Java多线程的并发控制机制,包括基本的同步方法、死锁问题以及高级并发工具如java.util.concurrent包的使用。通过分析多线程环境下的竞态条件、资源争夺和线程协调问题,我们提出了一系列实现和优化策略,旨在帮助开发者构建更加健壮、高效的多线程应用。
7 0