用java语言撰写程序已经多年,时不时问问自己,真的了解jdk的api的设计原理,而不是靠的死记硬背学会使用,然而身边大多数程序员会告诉我,会用就可以,是事实不是这样的,去年我面试阿里失败后,我就在反思我的学习方式,现在做一些调正,提高要求,不仅要会用,还要看懂源码,学习设计api的思想。

  从下图看,整个java的生态很大,想要每个了解到位是不可能的,先从java语言的api中的java.util.concurrent包中并发编程开始。

  在面试时,你会发现不同的人对并发有着不一样的理解和看法,正确的理解并发摘取了网上的一句解释很到位的:计算机用户理所当然地认为他们的系统一次可以做多件事。他们假设他们可以继续在文字处理器中工作,而其他应用程序则下载文件,管理打印队列和流音频。即使是单个应用程序通常也希望一次完成多个任务。而可以执行这样操作的软件我们叫它并发软件。所以在5.0以后java就支持了并发执行任务。

线程对象

  每个线程都与该类的实例相关联 Thread。使用Thread对象创建并发应用程序有两种基本策略。

  • 要直接控制线程创建和管理,只需Thread在应用程序每次启动异步任务时进行实例化。
  • 要从应用程序的其余部分抽象线程管理,请将应用程序的任务传递给执行程序。 

创建和定义线程

  创建实例的应用程序Thread必须提供将在该线程中运行的代码。有两种方法可以做到这一点:

  提供一个Runnable对象。该 Runnable接口定义了一个方法,run,意在包含在线程执行的代码。Runnable对象被传递给Thread构造函数,如:

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();
    }

}

  子类继承ThreadThread类本身实现了Runnable,虽然它的run方法不起作用。应用程序可以子类化Thread,提供自己的实现run,如 

public class HelloThread extends Thread {

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

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

}

  请注意,两个示例都会调用Thread.start以启动新线程。我们应该使用哪一个?

  第一个使用Runnable对象的习语更为通用,因为该Runnable对象可以继承一个类以外的类Thread第二个习语在简单的应用程序中更容易使用,但受到任务类必须是后代的限制ThreadThread类定义了大量的线程管理有用的方法。这些static方法包括提供有关调用方法的线程的信息或影响其状态的方法。

              ————————————————————————–面试题和总结————————————————————–

  面试题分享:有几种方式创建线程,每种方式有什么不同,各有什么优劣?

  这是经常问到的面试题,旨在考查对多线程编程了解的程度,很多也是从网上直接下载下来的题目,在企业里很少使用到多线程编程,都在写业务代码,但是这样一问就知道你在上架公司担任什么水准的职位,什么职位就会去考虑什么问题,我们想更好的发展就必须知道其使用的场景和基本原理,以备工作和面试的需要。

  Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用三种方式来创建线程,如下所示:

  1)继承Thread类创建线程

  2)实现Runnable接口创建线程

  3)使用Callable和Future创建线程

  回答出①和②已经可以算是初步了解些,能够说出第三种与前两种区别的人初级和中级和很少,所以认真对待这道面试题。

  接口Future表示异步计算的结果。提供方法以检查计算是否完成,等待其完成,以及检索计算结果。

 interface ArchiveSearcher { String search(String target); }
 class App {
   ExecutorService executor = ...
   ArchiveSearcher searcher = ...
   void showSearch(final String target)
       throws InterruptedException {
     Future<String> future
       = executor.submit(new Callable<String>() {
         public String call() {
             return searcher.search(target);
         }});
     displayOtherThings(); // do other things while searching
     try {
       displayText(future.get()); // use future
     } catch (ExecutionException ex) { cleanup(); return; }
   }
 }

  FutureTask类是的一个实现Future一个实现Runnable,所以可以通过执行Executor例如,上述结构submit可以替换为:

 FutureTask<String> future =
   new FutureTask<String>(new Callable<String>() {
     public String call() {
       return searcher.search(target);
   }});
 executor.execute(future);

  接口Callable <V>

  这是一个功能接口,因此可以用作lambda表达式或方法引用的赋值目标。

call()

计算结果,如果无法执行,则抛出异常。

 

版权声明:本文为zhikou原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/zhikou/p/9315446.html