创建线程的3种方式,以及它们的优缺点

2022-07-07  本文已影响0人  程就人生

创建一个线程,很多人会想到两种方式,一种是继承Thread类,一种是实现Runnable接口,如果需要返回参数,使用哪一种呢?现在就来说说三种不同的创建线程方式,以及它们的优缺点。

第一种方式,继承Thread类

/**
 * 实现方式一:1.继承Thread类
 * @author 程就人生
 * @Date
 */
public class Thread1 extends Thread{

  /**
   * 重写run方法
   */
  public void run() {
    System.out.println("当前线程名称:" + Thread.currentThread().getName());
  }
}

创建过程:
1.定义Thread类的子类,重写run方法;
2.创建Thread子类的实例;
3.调用该实例的start方法启动线程。

public static void main(String[] argo){
    
    // 2.创建Thread子类的实例
    Thread1 thread1 = new Thread1();
    // 3.调用线程对象的start来启动该线程
    thread1.start();
}

通过定义一个Thread的子类,创建一个线程对象,并调用start方法来启动线程对象,使用起来非常简单。

第二种方式,实现Runnable接口

/**
 * 线程实现方式二:1.实现Runnable接口
 * 线程任务类
 * @author 程就人生
 * @Date
 */
public class ThreadTarget implements Runnable{
  
  private int i;

  public ThreadTarget(int i) {
    this.i = i;
  }

  /**
   * 重写run方法
   */
  @Override
  public void run() {
    System.out.println("当前线程名称:" + Thread.currentThread().getName() + ", i=" + i);
  }
}

创建过程:
1.定义Runnable接口的实现类,重写run方法,作为线程任务类;
2.创建Runnable实现类的实例,并以该实例为target创建线程实例;
3.调用线程实例的start方法启动线程。

public static void main(String[] argo){ 
    // 3.创建Runnable实现类的实例,它是线程对象运行的target
    ThreadTarget threadTarget = new ThreadTarget(1);
    // 该Thread对象才是真正的线程对象
    Thread thread = new Thread(threadTarget);
    // 4.调用线程对象的start来启动该线程
    thread.start();
    // 共享成员变量
    new Thread(threadTarget).start();
}

如果线程任务类里有实例变量,那么多个线程可以共享这些实例变量。

特点:多个线程可以使用一个线程任务类,并且共享该类中的实例变量。

第三种方式,实现Callable接口

import java.util.concurrent.Callable;
/**
 * 线程实现方式二:1.实现Callable接口
 * @author 程就人生
 * @Date
 */
public class ThreadCall implements Callable<Integer>{
  /**
   * 2.重写call方法
   */
  @Override
  public Integer call() throws Exception {
    System.out.println("当前线程名称:" + Thread.currentThread().getName());
    return 1;
  }
}

创建过程:
1.定义Callable接口的实现类,并重写call方法;
2.创建Callable实现类的对象,使用FutureTask包装该对象,并以此为target创建线程对象;
3.调用线程对象的start方法启动该线程对象;
4.通过FutureTask包装对象获取返回值。

public static void main(String[] argo){
    try {
      // 3.创建Callable对象
      ThreadCall call = new ThreadCall();
      // 4.使用FutureTask来包装Callable对象
      FutureTask<Integer> futureTask = new FutureTask<Integer>(call);
      // 该Thread对象才是真正的线程对象
      Thread thread3 = new Thread(futureTask);
      // 4.调用线程对象的start来启动该线程
      thread3.start();
      System.out.println("有返回值的线程,返回值为:" + futureTask.get());
    } catch (InterruptedException e) {
      e.printStackTrace();
    } catch (ExecutionException e) {
      e.printStackTrace();
    }
  }

特点:call方法比run方法更强大,可以设置返回值;Callable接口有泛型限制,可以控制返回值的类型。

最后总结

本文简单列举了三种创建线程对象的方式。第一种最简单,定义一个Thread子类,直接创建一个线程对象。第二种稍微复杂一点,粒度又细了一点,定义一个实现Runnable接口的线程任务类,在这个线程任务类的基础上,创建一个或多个线程,多个线程之间可以共享线程任务类的实例。第三种最复杂,定义一个实现Callable泛型接口的任务实现类,通过FutureTask包装,在此基础上创建一个或多个线程,每个线程都可以有返回值。具体使用哪种,还要看实际的业务场景。

上一篇下一篇

猜你喜欢

热点阅读