当前位置: > 关于睿道 > 新闻中心 > 行业动态
  • 睿道简介
  • 新闻中心
  • 园区环境
  • 联系我们
  • 面试重点考题“线程”问题你会了吗?

    2019-10-17 来源:Neuedu东软睿道

    面试研发岗位的小伙伴可能发现了,面试官经常会提问有关“线程”的问题,比如,线程是什么?多线程的常见应用场景是什么?创建线程的方式有哪几种?这些方式分别有什么优点?等等。

    线程问题这么受面试考官青睐,重要程度自然不必说啦。今天,我们就来讲一下“线程”的问题。

    问题一:线程是什么?

    线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中;

    一个进程可以并发多个线程,每条线程并行执行不同的任务;

    多线程程序设计的好处是提高了程序的执行吞吐率和执行效率。

    问题二:多线程的常见应用场景

    后台任务,例如:定时向大量用户推送信息例如广告邮件,不胜其扰,大家一定有体会

    异步处理,例如:批量I/O操作,发微博、记录日志等

    分布式计算,共享稀有资源和平衡负载

    web服务器本身,例如:Tomcat

    问题三:创建线程有几种方式?

    使用多线程第一步就是创建线程,今天给大家分享6种创建线程的方式。

    方式一:继承Thread类并重写run()方法


    public class ThreadDemo1 extends Thread

     {

           private String name;

           public ThreadDemo1 (String name)

    {

    this.name=name;

    }


     @Override 

    public void run() 

    System.out.println(this.name+"线程运行了"); 

    public static void main(String[] args)

     { 

    new ThreadDemo1(“线程一”).start(); 

    new ThreadDemo1(“线程二”).start();

    }

    总结:这是最简单的创建方式,但弊端是占用了唯一一次继承机会,因为Java是单继承,如果这个类必须继承其它类,就无法采用这种创建方式了。


    方式二:实现Runnable接口

    public class ThreadDemo2 implements Runnable 

    @Override public void run() 

    System.out.println(Thread.currentThread().getName() + "线程运行了");

    public static void main(String[] args) 

    new Thread(“线程1”,new ThreadDemo2()).start(); 

    new Thread(“线程2”,new ThreadDemo2()).start(); 

    }

    总结:这种创建方式最大的优点是代码简洁,只需关注线程代码本身即可;缺点是代码复用性较差。如果线程代码只使用一次,可以考虑这种方式,现在多数使用lambda表达式(JAVA8+)。


    方式三:匿名内部类

    public classThreadDemo3 

    {

     public static void main(String[] args) 

    { // 第一种Thread匿名子类,重写Trun()方法 

    new Thread() {

     @Override public void run() 

    {

     System.out.println(" 匿名Thread子类,线程运行了"); 

    } }.start(); 

    // 第二种Runnable匿名实现类,实现run()方法 

    new Thread(new Runnable() { 

    @Override public void run()

     { 

    System.out.println( " Runnable匿名实现类,线程运行了"); 

    } }).start(); 

    // 第三种使用lambda表达式,简化代码

    new Thread(()->{ 

    System.out.println("Lambda表达式线程类,线程运行了"); 

    }).start(); 

    }

    总结:这种创建方式最大的优点是代码简洁,只需关注线程代码本身即可;缺点是代码复用性较差。如果线程代码只使用一次,可以考虑这种方式,现在多数使用lambda表达式(JAVA8+)。


    方式四:使用Timer定时器(java.util.Timer)


    public class ThreadDemo4 

    {

     public static void main(String[] args)

     {    //创建Timer定时器

    Timer timer = new Timer(); 


    // 每隔1秒执行一次 

    timer.schedule(new TimerTask() 

    @Override 

    public void run()

     { 

    System.out.println(Thread.currentThread().getName() + " is running"); 

    }, 0 , 1000); 

    }

    }

    总结:TimerTask实现了Runnable接口,Timer定时器可以安排线程“执行一次”或定期“执行多次”。在实际开发过程中,经常需要周期性的操作,如每几分钟执行某项操作等。对于这类需求,最方便高效的实现方式就是使用java.util.Timer工具类。



    方式五:使用线程池

    class MyThread  implements Runnable

    {

    @Override

    public void run() 

    {

    System.out.println(Thread.currentThread().getName()+“正在运行”);

    }

    }

    public class ThreadDemo5 

    public static void main(String[] args) 

          //池中有十个线程

    ExecutorService threadPool = Executors.newFixedThreadPool(10); 

    for (int i = 0; i < 1000; i++) 

    {      

    threadPool.execute(new MyThread()); 

    }

    总结:线程池是多个线程的集合,使用线程池我们不需要自己创建线程,将线程任务提交给线程池即可。线程池有以下两大优点:1.可重用已有的线程继续执行任务,减少线程创建和销毁时造成的损耗从而提高系统响应速度;2.通过对可执行线程进行合理管理,根据系统承受能力调整可运行线程数量的大小等。最佳实践Tomcat服务器处理用户请求的线程,就是使用线程池进行管理。

    方式六:实现Callable接口(java.util.concurrent.Callable)

    public class ThreadDemo6 implements Callable 

    @Override 

    public String call() throws Exception 

    {    //实现call方法

    System.out.println( " is running"); 

    return “线程执行后结果”; 

    public static void main(String[] args) throws Exception 

    FutureTasktask = new FutureTask<>(new ThreadDemon6());

    new Thread(task).start(); 

    System.out.println("等待线程执行结束");

    String result = task.get(); 

    System.out.println("线程执行结果:" + result); 

    }

    总结:Java多线程的核心方法run是没有返回值的,如需run方法执行后的结果,必须等待run方法计算完,无论计算过程多么耗时。而Future模式恰恰能解决这一困境。实现Callabe接口,可以获得线程执行后的结果。


    上面介绍了那么多创建线程的方式,总结而言,分为两大类:

    继承Thread类并重写run()方法

    实现Runnable接口的run()方法


    上面的内容,你学会了吗?


    彩蛋:某大型互联网公司面试真题

    public class ThreadExam

    {

     public static void main(String[] args)

    {

    new Thread(

    ()-> { System.out.println("Runnable: 运行" ); }

    {

    @Override public void run() { System.out.println("Thread: 运行"); } 

    }.start();

    }