• 面试——并发基础知识1


    1、进程和线程之间有什么不同?
      一个进程是一个独立(self contained)的运行环境,它可以看作一个程序或者应用。
     线程是进程中一个执行任务。
     线程可以称为轻量级的进程,只需要少量资源变可以创建,创建之后驻留在进程中,可以共享进程中资源。

    2、多线程编程的好处?
     首先多线程并发可以提高程序的效率,CPU不会因为等待资源而进入空闲状态,多线程编程比多进程执行任务更节省资源

    3、用户线程和守护线程有什么区别?
     用户线程指得是我们再程序中创建的线程,
     守护线程指得是在后台执行的并且不会阻止JVM终止的线程,守护线程创建的子线程也是守护线程。
     当没有用户线程在运行的时候,jvm会关闭程序并且退出。

    4、如何创建一个线程?
     第一种:实现Runnable接口,然后通过参数传递给Thread的构造函数,创建一个Thread对象。
     第二种:直接继承Thread类
     了解更多Java中创建线程https://www.journaldev.com/1016/java-thread-example

    5、线程有几种不同的生命周期(状态)?

    • NEW  :新建一个线程;
    • Runnable :调用线程的start()方法时;
    • Running : 线程调度器会为Runnable线程池中的线程分配CPU时间并且将它们的状态改变为Running;
    • Waiting :
    • Blocked
    • Dead

      

      了解更多线程生命周期https://www.journaldev.com/1044/thread-life-cycle-in-java-thread-states-in-java


    6、可以直接调用Thread类的run()方法么?
     可以,但是如果直接调用,行为相当于调用于普通方法一样,为了在新的线程执行我们的代码,必须使用Thread.start()方法

    7、如何让正在运行的线程暂停一段时间?
     可以通过Thread.sleep(long mills)方法让线程暂停一段时间。

    8、线程优先级如何理解?
     每一个线程都有优先级的。高优先级的线程会在运行时具有优先权,但是并不能保证它一定会比优先级低的线程先执行,
     因为这依赖于线程调度的实现,而实现又和操作系统有关;优先级从低到高(1-10).

    9、什么是线程调度器(Thread Scheduler)和时间分片(Time Slicing)?
     线程调度器是一个操作系统服务,它负责为Runnable状态的线程分配CPU时间。也就是说,一个线程一旦创建并启动它,它的执行依赖于线程调度器实现。
     时间分片是指将可用的CPU时间分配给可用的Runnable线程的过程,分配CPU时间可以基于线程优先级或者线程等待时间。

    10. 在多线程中,什么是上下文切换(context-switching)?

     上下文切是存储和回复CPU状态的过程,它使得线程执行能从中断点恢复执行,它是多任务操作系统和多线程环境的基本特征。


    11. 如何确保main()方法所在的线程是Java程序最后结束的线程?

     使用Thread类的join()方法来阻塞main主线程,来保证所有的用户线程执行完。
     更多了解Thread类的joint()方法https://www.journaldev.com/1024/java-thread-join-example


    12.线程之间是如何通信的?

     在一个进程中的多线程是可以共享资源的,它们之间的通信通过Object类中wait() otify() otifyAll()方法来了解资源的锁的状态。
     更多了解这里https://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example


    13.为什么线程通信的方法wait(), notify()和notifyAll()被定义在Object类里?

     Java的每个对象都有一个锁,并且wait().notify()等方法用于等待对象的锁或者和其他线程对象进行通信,由于Java的线程中并没有可提供任何对象使用的锁和同步器。


    14. 为什么wait(), notify()和notifyAll()必须在同步方法或者同步块中被调用?

     当一个线程需要调用对象的wait()方法的时候,这个线程必然已经持有了该对象的锁,接着它就会释放该对象锁进入等待状态直到其他线程调用这个对象的notify()方法
     同样,当一个线程需要调用对象的notify()方法的时候,它会释放这个对象锁,以便其他等待的线程就可以得到这个对象锁,
     由于所有这些方法都需要线程持有对象锁,这样就只能通过同步来实现,所以只能在同步方法或者同步块中实现调用。 


    15. 为什么Thread类的sleep()和yield()方法是静态的?

     Thread类的sleep()和yeild()方法将在当前正在执行的线程上运行。所以其他处于等待的线程上调用这些方法时没有意义的,所以这些方法时静态的。

    16.如何确保线程安全?

     线程不安全:多个线程对同个资源做竞争修改的情况。
     保证线程安全的方式:锁,同步,使用原子类,使用volatile关键字,使用不变类和线程安全类
      
     本文转发自技术世界,原文链接 http://www.jasongj.com/java/thread_safe/
     详细了解在线程安全教程中https://www.journaldev.com/1061/thread-safety-in-java

    17. volatile关键字在Java中有什么作用?

     使用volatile关键字修饰变量时,所有线程都会直接读取该变量并且不缓存它,这就确保读取到的变量时同内存中是一致的。但是并不能多线程往这个变量写是一致的。

    18、同步方法和同步块,哪个是更好的选择?
     同步块是更好的选择,因为它不会锁住整个对象(也可以锁住整个对象)。
     同步方法会锁住整个对象,即使这个类中有多个不相关联的同步块,这样会导致线程会停止执行并等待获取该对象上的锁。
     更多了解https://blog.csdn.net/silencecarrot/article/details/52415704


    19.如何创建守护线程?

     调用Thread类的setDaemon(true)方法可以将线程设置为守护线程。注意:需要再调用start()方法前调用该方法,否则会抛出IllegalThreadStateException异常。

    20. 什么是ThreadLocal?

     ThreadLocal用于创建线程的本地变量,一个对象所有线程会共享它的全局变量,所以这些变量不安全,当然可以用同步技术,但是也可以选择ThreadLocal变量。
     每个线程都会拥有他们自己的Thread变量,可以调用get()set()方法来获取其默认值或者在线程内部改变他们的值。
     ThreadLocal实例通常是希望他们同线程状态关联起来是private static 属性。
     了解更多在ThreadLocal例子 https://www.journaldev.com/1076/java-threadlocal-example

    21、什么是java线程转储(Thread Dump),如何使用它?

     线程转储是一个JVM活动线程的列表,它对于分析系统瓶颈和死锁非常有用。获取线程转储的方式——使用Profiler,Kill -3命令,jstack工具等等,

     更多了解产生线程转储http://www.journaldev.com/1053/how-to-generate-thread-dump-in-java

    22. 什么是死锁(Deadlock)?如何分析和避免死锁?

     死锁:两个以上的线程永远阻塞的情况。
     分析死锁的方式:查看java应用程序的线程转储,找出那些状态为BLOCKED的线程和他们等待的资源。
     每个线程都有一个唯一的id,用这个id我们可以找出哪些线程已经用有了它的对象锁。
     避免嵌套锁:只在需要的地方使用锁和避免无限期等待
     更多了解如何分析死锁 https://www.journaldev.com/1058/deadlock-in-java-example

    23、什么是Java Timer类?如何创建一个有特定时间间隔的任务?
     java.util.Timer是一个工具类,可以用于安排一个线程在未来的某个特定的时间执行,Timer类可以实现一次性任务或者周期任务。
     java.util.TimerTask是一个实现了Runnable接口的抽象类,需要继承这个类来创建我们自己的定时任务并且使用Timer来安排其执行。
     更多了解java Timer的例子https://www.journaldev.com/1050/java-timer-timertask-example


    24、什么是线程池?如何创建一个java线程池
     一个线程池管理了一组工作线程,同时它还维持了一个用于放置等待执行的任务队列。
     java.util.concurrent.Executors提供了java.util.concurrent.Executor接口的实现用于创建线程池。
     线程池例子https://www.journaldev.com/1069/threadpoolexecutor-java-thread-pool-example-executorservice展现如何创建和使用线程池。
     ScheduledThreadPoolExecutorhttps://www.journaldev.com/2340/java-scheduler-scheduledexecutorservice-scheduledthreadpoolexecutor-example创建一个周期任务

    1、什么是原子操作?在Java Concurrency API中有哪些原子类(atomic classes)?
     原子操作是指一个不受其他操作影响的操作任务单元。单元操作是在多线程环境下不免数据不一致必须的手段。
     i++并不是一个原子操作,所以当一个线程读取它的值并加1时,另外一个线程有可能会读到之前的值,这会引发错误。
     为了解决这个问题,必须保证增加操作是原子的,JDK1.5之前可以使用同步,JDK1.5,java,util.concurrent.atomic包提供int和long类型的包装类,
     它们可以自动保证对于它们的操作是原子并且不需要同步
     更多了解Java的atomic类https://www.journaldev.com/1095/atomicinteger-java

    2、Java Concurrency API中的Lock接口(Lock interface)是什么?对比同步它是什么优势?
     Lock接口比同步方法和同步块提供了更具扩展性的锁操作。它们运行更灵活的结构,可以具有完全不同的性质,并且可以支持多个相关类的条件对象
     优势:
     可以使锁更公平
     可以使线程在等待锁的时候相应中断
     可以让线程在尝试获取锁,并在无法获取锁的时候立即返回或者等待一段时间
     可以在不同的范围,以不同的顺序获取和释放锁
     更多了解关于锁的例子https://www.journaldev.com/2377/java-lock-example-reentrantlock

    3、什么是Executors框架?
     Executor框架是在java5被引入,是一个根据一组执行策略调用,调度,执行和控制的异步任务的框架。
     可以通过Executor框架很方便的创建一个线程池,可以限制线程的数量并可以回收这些线程,避免通过无限制创建线程导致内存溢出。
     了解如何使用Executor框架创建一个线程池。

    4、什么是阻塞队列?如何使用阻塞队列来实现生产者-消费者模型?
     java.util.concurrent.BlockingQueue的特性是:当队列是空的时,从队列中获取或删除元素的操作会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞。
     阻塞队列不接受空值,向队列添加空值,会抛出NullPointerException.
     阻塞队列的实现都是线程安全的,所有的查询方法都是原子的,并且使用内部锁或者其他形式的并发控制。
     BlockingQueue接口是java.collection框架的一部分,主要用于实现生产者-消费者问题
     更多了解如何使用阻塞队列实现生产者-消费者问题 https://www.journaldev.com/1034/java-blockingqueue-example


    5、什么是Callable和Future?
     java5在concurrency包中引入了java.util.concurrent.Callable接口,它和Runnable接口相似,但它可以返回一个对象或者抛出一个异常。
     Callable接口使用泛型去定义它的返回类型,Executors类提供了一些有用的方法去在线程池中执行Callable内的任务,由于Callable任务是并行的,
     我们必须等待它返回的结果。在线程池提交Callable任务后返回了一个Futrue对象,使用它我们可以知道Callable任务的状态和得到Callable返回的执行结果。
     Future提供了get()方法让我们可以等待Callable结束并获取它的执行结果
     更多了解关于Callable,Future的例子 https://www.journaldev.com/1090/java-callable-future-example


    6、什么是FutureTask?
     FutureTask是Future的一个基础实现,我们可以将它同Executors使用处理异步任务。通常我们不需要使用FutureTask类,可以重写Future接口的一些方法。
     更多了解Java FutureTask例子 https://www.journaldev.com/1650/java-futuretask-example-program


    7、什么是并发容器的实现?
     java集合类都是快速失败的,这就意味着当集合被改变且一个线程在使用迭代器遍历集合的时候,迭代器的next()方法将抛出ConcurrentModificationException异常。
     并发容器支持并发的遍历和并发的更新。
     主要的并发容器类有ConcurrentHashMap,CopyOnWriteArrayList和CopyOnWriteArraySet
     更多了解 如何避免ConcurrentModificationException https://www.journaldev.com/378/java-util-concurrentmodificationexception


    8、Executors类是什么?
     Executors为Executor,ExecutorService,ScheduledExecutorService,ThreadFactory和Callable类提供了一些工具方法。
     Executors可以用于方便的创建线程池。


    原创文章,转载请注明: http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-answers/

  • 相关阅读:
    《剑指offer》— JavaScript(1)二维数组中的查找
    《JavaScript高级程序设计(第三版)》-3
    HTML+CSS基础
    HTML5新增属性
    《javascript高级程序设计(第3版)》-1
    wp8.1 Study7: ListView 和GridView应用
    wp8.1 Study6: App的生命周期管理
    WP8.1 Study5:Data binding数据绑定
    WP8.1 Study4:WP8.1中控件集合应用
    WP8.1 Study3:WP8.1中Animation应用
  • 原文地址:https://www.cnblogs.com/atomicbomb/p/9026305.html
Copyright © 2020-2023  润新知