面试题:线程的几种创建方法

创建线程的四种方式:

  1. 继承Thread类,并复写run方法,创建该类对象,调用start方法开启线程。此方式没有返回值。

    // 创建线程对象
    Thread t = new Thread() {
    public void run() {
    // 要执行的任务
    }
    };
    // 启动线程
    t.start()
    
  2. 实现Runnable接口,复写run方法,创建Thread类对象,将Runnable子类对象传递给Thread类对象。调用start方法开启线程。此方法2较之方法1好,将线程对象和线程任务对象分离开。降低了耦合性,利于维护。此方式没有返回值。

    Runnable runnable = new Runnable() {
    public void run(){
    // 要执行的任务
    }
    };
    // 创建线程对象
    Thread t = new Thread( runnable );
    // 启动线程
    t.start();
    
  3. 创建FutureTask对象,创建Callable子类对象,复写call(相当于run)方法,将其传递给FutureTask对象(相当于一个Runnable)。 创建Thread类对象,将FutureTask对象传递给Thread对象。调用start方法开启线程。这种方式可以获得线程执行完之后的返回值。该方法使用Runnable功能更加强大的一个子类.这个子类是具有返回值类型的任务方法。

    // 创建任务对象
    FutureTask<Integer> task3 = new FutureTask<>(() -> {
    log.debug("hello");
    return 100;
    });
    // 参数1 是任务对象; 参数2 是线程名字,推荐
    new Thread(task3, "t3").start();
    // 主线程阻塞,同步等待 task 执行完毕的结果
    Integer result = task3.get();
    log.debug("结果是:{}", result);
    
  4. 线程池

  • 提供了一个线程队列,队列中保存着所有等待状态的线程。避免了创建与销毁额外开销,提高了响应的速度。

常见的几种状态

【初始状态】仅是在语言层面创建了线程对象,还未与操作系统线程关联
【可运行状态】(就绪状态)指该线程已经被创建(与操作系统线程关联),可以由 CPU 调度执行
【运行状态】指获取了 CPU 时间片运行中的状态
当 CPU 时间片用完,会从【运行状态】转换至【可运行状态】,会导致线程的上下文切换

【阻塞状态】
如果调用了阻塞 API,如 BIO 读写文件,这时该线程实际不会用到 CPU,会导致线程上下文切换,进入【阻塞状态】
等 BIO 操作完毕,会由操作系统唤醒阻塞的线程,转换至【可运行状态】
与【可运行状态】的区别是,对【阻塞状态】的线程来说只要它们一直不唤醒,调度器就一直不会考虑调度它们
【终止状态】表示线程已经执行完毕,生命周期已经结束,不会再转换为其它状态

原文地址:https://www.cnblogs.com/dalianpai/p/14168567.html