美文网首页互联网科技Java
8种创建Java线程的方式,你知道几个?

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

作者: 程序员追风 | 来源:发表于2019-10-09 19:30 被阅读0次

作者:唐彤

简介

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

image

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

 @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接口

 @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 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接口

 @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 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 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 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)。

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

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

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

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

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

运行结果如下:

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 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类的源码:

 // 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线程的方式,你知道几个?

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

  • 线程

    java 中创建线程有哪几种方式? Java中创建线程主要有三种方式: 一、继承Thread类创建线程类 (1)定...

  • 高质量安卓面试题2018

    公司一 说下你所知道的设计模式与使用场景 java语言的特点与是OOP思想 说下java中的线程创建方式,线程池的...

  • Java多线程:线程的创建与启动

    # 面试题: Java中创建线程有几种方式。 不同的创建方式有什么区别。 如何启动一个线程。 # Java中创建线...

  • 【java基础】线程

    java基础 线程 参考详细:Java之多线程 一、创建线程 创建线程常见有两种方式,另外有两种新增方式 1.Th...

  • Java基础(六)

    多线程 Java多线程并发 1.1 JAVA 并发知识库 1.2 JAVA 线程实现/创建方式 1.2.1 继承 ...

  • java中创建线程池的方式

    创建线程池的方式: 使用Java提供的用于管理线程池的接口ExecutorService 创建线程池,共有四种方式...

  • 1 Java线程知识

    Java三种创建线程的方式:

  • 多线程 学习1

    一、创建线程方式 java创建线程的方式,主要有三种:类Thread、接口Runnable、接口Callable。...

  • Java 创建线程的 3 种方式

    Java 创建线程的 3 种方式 Java 创建线程有多种方式,我们经常使用的一般为以下 3 种。 直接继承 Th...

网友评论

    本文标题:8种创建Java线程的方式,你知道几个?

    本文链接:https://www.haomeiwen.com/subject/nzzgpctx.html