01-实现线程

nobility 发布于 2021-04-10 2589 次阅读


实现线程

从Java官方文档中可以查看到,无论是JDK8还是JDK11中对线程的实现方式只有两种,一种是继承Thread类重写run()方法,一种是实现Runnable接口实现run()方法并传递给Thread类实例

Thread源码中也可以看出,无论是哪种方式,最终还是调用Threadrun()方法,所以准确的说,创建线程只有一种方式,就是构造Thread类,而实现线程的执行单元有两种方式

继承Thread类方式

public class MyThread extends Thread{
  @Override
  public void run() {
    System.out.println("继承Thread,复写run()方法");
  }

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

实现Runnable接口方式

public class MyRunnable implements Runnable {
  @Override
  public void run() {
    System.out.println("实现Runnable,实现run()方法");
  }

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

两种方式对比

通常情况下会优先选择实现Runnable接口方式

  • 避免由单继承局限带来的影响

  • 从代码架构考虑线程所执行的任务应该与线程创建动作应该是解耦的

  • 线程创建的操作对于CPU消耗是比较大的,继承Thread类实现的线程,每次只能新建的独立的线程,而实现Runable接口实现线程,可通过线程池之类的工具来降低创建线程的性能损耗(线程池只能放入Runable或Callable接口实现类,不能直接放入继承Thread的类)

两种方式的本质区别,从Thread的源码中可以看出,若使用实现Runnable接口方式,其实是直接执行了run()方法;若使用继承Thread类方式其实是将run()方法进行重写

class Thread implements Runnable {
  //省略...
  private Runnable target;  //用于构造函数接收Runnable接口实例
  //省略...
  @Override
  public void run() {
    if (target != null) {  //判断该线程中是否接收过Runnable接口实例
      target.run();
    }
  }
  //省略...
}

从源码中可以看出,同时使用两种方式实现线程时,实现Runnable接口方式将失效

public static void main(String[] args) {
  new Thread(() -> System.out.println("Runnable中的run()方法")) {
    @Override
    public void run() {
      System.out.println("Thread中的run()方法");
    }
  }.start();
}

其他封装层面的创建线程方式

虽然多线程的实现方式在代码层面的写法有很多,但是本质上都是对实现Runnable接口方式,继承Thread类方式的封装

实现Callable接口方式

public class MyCallable implements Callable<String> {
  @Override
  public String call() {
    System.out.println("当前线程正在执行:" + Thread.currentThread().getName());
    return "Callable中的call()方法的返回值";
  }

  public static void main(String[] args) {
    FutureTask<String> futureTask = new FutureTask<>(new MyCallable());  //使用FutureTask类对Callable实现类进行包装
    new Thread(futureTask).start();  //使用Thread来启动线程
    try {
      String result = futureTask.get();  //使用FutureTask的get()方法来线程获取返回值
      System.out.println(result);
    } catch (InterruptedException e) {
      e.printStackTrace();
    } catch (ExecutionException e) {
      e.printStackTrace();
    }
  }
}

线程池方式

public static void main(String[] args) {
  ExecutorService executorService = Executors.newCachedThreadPool();  //创建线程池
  for (int i = 0; i < 1000; i++) {
    //向线程池中提交1000个任务
    executorService.submit(() -> System.out.println("当前线程正在执行:" + Thread.currentThread().getName()));
  }
}

定时器方式

public static void main(String[] args) {
  Timer timer = new Timer();  //创建定时器
  timer.scheduleAtFixedRate(new TimerTask() {  //传递定时任务对象
    @Override
    public void run() {
      System.out.println("当前线程正在执行:" + Thread.currentThread().getName());
    }
  }, 0, 1000);  //延时0秒,间隔1秒
}
此作者没有提供个人介绍
最后更新于 2021-04-10