美文网首页
创建线程的3种方式,以及它们的优缺点

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

作者: 程就人生 | 来源:发表于2022-07-07 21:52 被阅读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包装,在此基础上创建一个或多个线程,每个线程都可以有返回值。具体使用哪种,还要看实际的业务场景。

    相关文章

      网友评论

          本文标题:创建线程的3种方式,以及它们的优缺点

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