面试官:请问实现多线程有几种方式?

应聘者:

  • 继承Thread类

  • 实现Runnable接口

  • 使用匿名内部类方式

  • 实现Callable接口

  • 使用线程池的方式

下面我们将对这五种方式进行详细的概述。


继承Thread类

Thread类本质上是实现了Runnable接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。例如:

 1public class MyThread extends Thread {  
2  public void run() {  
3   System.out.println("MyThread.run()");  
4  }  
5}  
6
7MyThread myThread1 = new MyThread();  
8MyThread myThread2 = new MyThread();  
9myThread1.start();  
10myThread2.start(); 


实现Runnable接口

1public class MyThread implements Runnable {  
2  public void run() {  
3   System.out.println("MyThread.run()");  
4  }  
5}  

为了启动MyThread,需要首先实例化一个Thread,并传入自己的MyThread实例:

1MyThread myThread = new MyThread();  
2Thread thread = new Thread(myThread);  
3thread.start(); 

事实上,当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用target.run(),参考JDK源代码:

1public void run() {  
2  if (target != null) {  
3   target.run();  
4  }  
5


使用匿名内部类

下面两种方式
  • 第一种相当于继承Thread类,子类的方式来实现;

  • 第二种将实现Runnable接口的类作为参数传进去;

 1public class MyThread {
2    public static void main(String[] args{
3        //第一种匿名内部类方式
4        new Thread(){
5            @Override
6            public void run() 
{
7                System.out.println("MyThread.run()" + Thread.currentThread().getName());  
8            }
9        }.start();
10        //第二种匿名内部类方式
11        new Thread(new Runnable(){
12            @Override
13            public void run() 
{
14                System.out.println("MyThread.run()" + Thread.currentThread().getName());
15            }
16        }).start();
17    }
18}

实现Callable接口

我们来看一下Callable接口源码定义如下:
1public abstract interface Callable<V>
2
{
3  public abstract V call()
4    throws Exception
;
5}
可以看到实现Callable接口是有返回值的,实现call接口,相比于Runnable接口是没有返回值的
  • 创建Callable接口的实现类 ,并实现Call方法 

  • 创建Callable实现类的实现,使用FutureTask类包装Callable对象,该FutureTask对象封装了Callable对象的Call方法的返回值 

  • 使用FutureTask对象作为Thread对象的target创建并启动线程 

  • 调用FutureTask对象的get()来获取子线程执行结束的返回值

 1public class MyThread implements Callable<Integer{
2    public static void main(String[] args) throws Exception {
3        MyThread myThread = new MyThread();
4        FutureTask<Integer> task = new FutureTask<Integer>(myThread);
5        Thread t = new Thread(task);
6        t.start();
7        Integer result = task.get();
8        System.out.println("线程执行的结果为:" + result);
9    }
10
11    @Override
12    public Integer call() throws Exception {
13        System.out.println("正在计算...");  
14        Thread.sleep(3000);
15        return 1;
16    }
17}

线程池创建线程

从java5开始,提供了一系列工厂方法用于创建线程池,返回的线程池都实现了ExecutorService接口
 1public class ThreadDemo {
2    //线程池数量
3    private static int POOL_NUM = 10
4    public static void main(String[] args) throws InterruptedException {
5        ExecutorService executorService = Executors.newFixedThreadPool(5);
6        for (int i = 0; i < POOL_NUM; i++) {
7            RunnableThread thread = new RunnableThread();
8            executorService.execute(thread);
9        }
10        // 关闭线程池
11        executorService.shutdown();
12    }
13}
14
15class RunnableThread implements Runnable {
16    @Override
17    public void run() {
18        System.out.println("通过线程池方式创建的线程:" + Thread.currentThread().getName()
19                + " ");
20    }
21}

转自:https://mp.weixin.qq.com/s/86I6HllQLNlWepTLdhobEQ