乐趣区

Java多线程实现的两种方式源自官方

来源概述

刚刚在准备面试刷题。于是想起好像有一个关于“Java 现成实现的方式”,于是百度(虽然盛传 * 度已死)、谷歌。然后结果。。。
[站外图片上传中 …(image-10f8bf-1569247170008)]

这坑不能忍啊!回答还能不能再给力一些。
这要是笔试或者面试有这个问题的话,那估计多少个面试机会都会死得不能再死了,还不知道到底根本原因是啥!!!这就相当可怕了。
于是找到官方 java tutorials 找结果:

意思就是实现线程只有两种方式

实现方式

第一种 实现 Runnalble 接口

Provide a Runnable object. The Runnable interface defines a single method, run, meant to contain the code executed in the thread. The Runnable object is passed to the Thread constructor, as in the HelloRunnable example:

public class HelloRunnable implements Runnable {public void run() {System.out.println("Hello from a thread!");
    }

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

}

第二种 继承 Thread 类

Subclass Thread. The Thread class itself implements Runnable, though its run method does nothing. An application can subclass Thread, providing its own implementation of run, as in the HelloThread example:


public class HelloThread extends Thread {public void run() {System.out.println("Hello from a thread!");
    }

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

}

小提示

Notice that both examples invoke Thread.start in order to start the new thread.

  1. 启动用线程对象的 start 方法调用,正如上面两个示例程序一样。
  2. 实现代码都是写在 run 方法里面,或者被 run 方法直接或间接调用。

疑问

  1. Thread 方法也是通过实现 Runnable 接口来实现的,是不是可以归结为一种呢?

官方两种,至于程序员自己嘛 哼哼哼 都懂都懂哈!!!

  1. 带返回值的线程实现方式(FutureTask + 实现 Callable 接口)、基于线程池的方式(Executors.new.*ThreadPool)、内部类实现方式不算么?

答: 这些都是拓展了上面两种的的其中一种,内部类是那那种方式,其它如:

  • 带返回值的线程实现方式(FutureTask + 实现 Callable 接口)
    FutureTask 实现了 Runnable 接口,其中就包括了调用接口 Callable 接口的 call 方法,所以是可以通过实现 Callable 就可以实现线程,那还是第一种线程实现方式。FutureTask 部分代码如下:
 public class FutureTask<V> implements RunnableFuture<V> {
  // 重写了 run 方法 只是内部实现
  public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable; // 使用到 Callable
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {result = c.call();  // 运行 call 方法
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);  // 设置返回值
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }
}
  • 基于线程池的方式(Executors.new.*ThreadPool)

其中 Executors.new.*ThreadPool 都是通过新建 ThreadPoolExecutor 类来实现的,而表示为工作任务的队列,所以这种也是第一种线程实现方式。Executors 部分代码如下:

  public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
      public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {// 工作线程队列 实现 Runnable 接口
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

总结

网上的坑还是有,一不小心就掉进去了。像这个显而易见的线程实现问题还是很容易知道有问题的,找出正解也没什么太大难度。但是想想我们平常遇到的问题是那么“层出不穷”?网上搜索到的解决方案又是如此“百花齐放”(管你对不对)。所以凡是问题都不要留心眼,根本不够用。

  • 学习资料,尽量从官方文档中学习,经典教材中学习;
  • 解决问题,多方搜索,各种推敲,免不了各种查源码;

—- 致困扰本帅多年的简单线程实现方式问题

退出移动版