二、创建线程的方式

继承Thread

  static class A extends Thread{
      @Override
      public void run() {
          System.out.println(Thread.currentThread().getName());
      }
  }
  public static void main(String[] args) {
        A a = new A();
        a.start();
  }

重写Runnable接口

static class B implements Runnable{
     public void run() {
         System.out.println(Thread.currentThread().getName());
     }
}
public static void main(String[] args) {
      B b = new B();
      Thread thread = new Thread(b);
      thread.start();
}

继承Thread和重写Runnable的区别:Thread类才是java对线程的唯一抽象,Runnable只是对业务的一种逻辑抽象,Thread可以接受任意一个Runnable的实例并执行。

注:Thread也是实现了Runnable接口的run方法。


Future

继承Thread或者重写Runnable都是不带返回值的创建方式,Future可以获取线程的返回值。

  • Future常用的实现类FutureTask实例化时接收一个抽象任务Callable
  • 将该Future的实例放入线程Thread中执行。
  • 通过Future的get()方法获取线程的返回值。
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(2000);
                return "success!";
            }
        });
        //FutureTask间接实现了Runnable接口的run
        Thread thread = new Thread(futureTask);
        thread.start();
        System.out.println(futureTask.get());
    }

新启线程有几种方式

这个问题的答案其实众说纷纭,有2种,3种,4种等等答案,建议比较好的回答是:

按照Java源码中Thread上的注释:

官方说法是在Java中有两种方式创建一个线程用以执行,一种是派生自Thread类,另一种是实现Runnable接口。

当然本质上Java中实现线程只有一种方式,都是通过new Thread()创建线程对象,调用Thread#start启动线程。

至于基于callable接口的方式,因为最终是要把实现了callable接口的对象通过FutureTask包装成Runnable,再交给Thread去执行,所以这个其实可以和实现Runnable接口看成同一类。

而线程池的方式,本质上是池化技术,是资源的复用,和新启线程没什么关系。所以,比较赞同官方的说法,有两种方式创建一个线程用以执行。


run和start的区别

Thread类是Java里对线程概念的抽象,可以这样理解:我们通过new Thread()其实只是new出一个Thread的实例,还没有操作系统中真正的线程挂起钩来。只有执行了start()方法后,才实现了真正意义上的启动线程。

从Thread的源码可以看到,Thread的start方法中调用了start0()方法,而start0()是个native方法,这就说明Thread#start一定和操作系统是密切相关的。

start()方法让一个线程进入就绪队列等待分配cpu,分到cpu后才调用实现的run()方法,start()方法不能重复调用,如果重复调用会抛出异常(注意,此处可能有面试题:多次调用一个线程的start方法会怎么样?)。

而run方法是业务逻辑实现的地方,本质上和任意一个类的任意一个成员方法并没有任何区别,可以重复执行,也可以被单独调用。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值