查看原文
其他

面试官:线程有几种创建方式?

Java4ye Java4ye 2022-09-04

滴滴~ ( •̀ ω •́ )y

「4ye」 今天来和大家分享下 「线程的创建方式」 啦😝

面试官:线程有几种创建方式?

这个也太简单了叭~ 😝

继承 Thread 类

步骤如下:

  1. 创建一个类继承  Thread
  2. 重写 run 方法
  3. 调用 Thread 类的 start 方法

类图~

代码如下

public class MyThread extends Thread{

    @Override
    public void run() {
        System.out.println(this.getClass().getSimpleName());
    }

    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        myThread.start();
    }

}

实现 Runnable 接口

步骤如下:

  1. 创建一个类实现 Runnable
  2. 重写 run 方法
  3. 将该类传递到  Thread  类的构造函数中
  4. 调用 Thread 类的 start 方法

代码如下

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println(this.getClass().getSimpleName());
    }

    public static void main(String[] args) {
        Thread myRunable=new Thread(new MyRunnable());
        myRunable.start();
    }
}

实现 Callable 接口,结合 Future 类获取返回值

特点:「可以获取线程的执行结果」

步骤如下:

  1. 创建一个类实现 Callable
  2. 重写 call 方法
  3. 创建 FutureTask 类,将该类传递到  FutureTask 类的构造函数中
  4. FutureTask  类传递到  Thread  类的构造函数中
  5. 调用 Thread 类的 start 方法
  6. 调用  FutureTask  类的 get 方法获取线程执行结果

FutureTask  类不知道大家熟不熟悉~ ,这是它的类图😋

可以发现它也是实现了这个 Runnable 接口 ,对比上面发现大家都实现了这个  Runnable 接口 。

然后传参到 Thread 类的构造器中,然后再去调用 start 方法去启动线程~🐷

代码如下

/**
 * @author Java4ye
 * @date 2021/4/15 6:58
 * @微信公众号:Java4ye
 * @GitHub https://github.com/RyzeYang
 * @博客 https://blog.csdn.net/weixin_40251892
 */

public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        return this.getClass().getSimpleName();
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        FutureTask<String> futureTask=new FutureTask<>(new MyCallable());
        Thread thread = new Thread(futureTask);
        thread.start();

        System.out.println(futureTask.get());
    }
}

通过线程池创建线程

线程池常见创建的方式有 5 种,具体的讲到 「线程池」 篇再展开~ 😝

这里的例子使用 「固定线程数量的线程池」 : newFixedThreadPool

步骤如下:

  1. 使用 Executors 创建线程池
  2. 创建一个实现  Runnable  或者  Callable  接口的类
  3. 针对 「没有」 返回值的,有 execute  方法
  4. 针对 「有」 返回值的有 , 有 submit  方法

代码如下

execute 方式
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.execute(new MyRunnable());
executor.shutdown();
submit 方式
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<String> future = executor.submit(new MyCallable());
System.out.println(future.get());
executor.shutdown();

有几种创建方式呢

嘿嘿  让我数一数 👉  一共有 四 种

事情真的这么简单吗~

当我无意间打开这个 Thread 的源码时,发现它居然说 有两种方式  , 就是前两种方式

虽然官方文档里说两种,但是 咱们和面试官说的时候肯定是说四种呀~  😋

多多益善 哈哈哈哈  ~

看到这个表情包表示还没结束呢 U•ェ•*U  哈哈哈

还可以和 面试官 说说下面这种异步处理结果的 ,Future 增强版!CompletableFuture (上面的 FutureTask  是阻塞版~)

CompletableFuture

为什么又来了一个 Future 呢?

主要是因为用 Future 获得异步执行结果时,要调用 「阻塞方法」 get() 或者轮询 isDone() 判断是否为true,这两种方法都会导致主线程被 「阻塞」 ,和我们想的异步不一样~ (我们需要它再帮我们处理下异步线程的执行结果呀😝)

所以在 JDK1.8 新引入了该类  CompletableFuture ,它实现了 Future 接口 ,又通过 CompletionStage 接口扩展了功能,增加了异步事件,实现异步处理线程执行完的结果,不用我们通过 Future 的阻塞方式去手动处理。

除了「异步执行结果」 外,它还可以 「异步处理异常」 ,具体看下面的例子😄

类图:

部分方法介绍

supplyAsync 表示创建带返回值的异步任务

runAsync 表示创建无返回值的异步任务

thenAccept  处理返回值,无返回结果

exceptionally 出现异常时,执行 exceptionally 中的回调方法。

正常例子

public class MyCompletableFuture {
    public static void main(String[] args) {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Java4ye");
        completableFuture.thenAccept(System.out::println);
        completableFuture.exceptionally(throwable -> {
            System.out.println(throwable.getMessage());
            return throwable.getMessage();
        });


    }
}

异常例子

public class MyCompletableFuture {
    public static void main(String[] args) {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> ""+1/0);
        completableFuture.thenAccept(System.out::println);
        completableFuture.exceptionally(throwable -> {
            System.out.println(throwable.getMessage());
            return throwable.getMessage();
        });


    }
}

嘿嘿 后面有机会再单独写一个介绍 CompletableFuture 的 ,里面还有很多方法 😝

总感觉这样结束也太干巴巴了  , 最后再和大家分享一道题 , 嘿嘿 你觉得答案是啥呢?

new Thread(()->{
    System.out.println("A");
}){
    @Override
    public void run() {
        System.out.println("B");
    }
}.start();

嘿嘿 这里的答案是 B , 看着花里胡哨的,其实是子类重写了父类的 run 方法 ~

回顾

目前 多线程 篇章 已经和小伙伴们分享了 这三个知识点啦  冲冲冲!😝

「我是 4ye 我们下期再见啦 

ヾ( ̄▽ ̄)Bye~Bye~」



时间片,上下文,调度算法等知识点~



带你从CPU看到进程~(硬核)


Java中的锁居然有这么多!


终于来到 ConcurrentHashMap 了~



喜欢的小伙伴们可以关注交个朋友呀!谢谢支持!!😝


可以的话再麻烦您点个赞呀👍 谢谢!



您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存