JAVA多线程高并发面试题总结

ReadMe : 括号里的内容为补充或解释说明。

多线程和高并发是毕业后求职大厂面试中必问的知识点,自己之前总是面试前才去找相关的知识点面试题来背背,隔段时间又忘了,没有沉淀下来,于是自己总结了下相关的知识点。

多线程

1. 进程和线程之间有什么不同?

  进程是一个独立的运行环境,它可以被看作是一个程序或者一个应用。而线程是在进程中执行的一个任务。进程是操作系统进行资源分配的基本单位,而线程是操作系统进行调度的基本单位。进程让操作系统的并发性成为可能,而线程让进程的内部并发成为可能。好比Java运行环境是一个(包含了不同的类和程序的)单一进程。

想理解的更深刻,请点击进程与线程的区别.

2. Thread 类中的start() 和run() 方法有什么区别?

1) start()被用来启动新的线程,run()不能。

2)start()不能被重复调用,run()可以。

3)start()中的run代码可以不执行完就继续执行下面的代码,即线程转换,如果直接调用run()必须等待其代码全部执行完才能继续执行下面的代码。

4)start()实现了多线程,run()没有实现多线程。

3.  在多线程中,什么是上下文切换?

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

4. Java中的volatile 变量是什么?

  volatile是一个特殊的修饰符,只有成员变量(类的成员变量、类的静态成员变量)才能使用它。

被volatile修饰之后就具备了两层语义:

  1)保证了不同线程对这个变量进行操作时的可见性(即一个线程修改了某个变量的值,这新值对其他线程来说是即刻可见的)。

  2)禁止进行指令重排序。

5. Java中堆和栈有什么不同?(相对于线程来说)

  栈是一块和线程紧密相关的内存区域。每个线程都有自己的栈内存,用于存储本地变量,方法参数和栈调用,一个线程中存储的变量对其它线程是不可见的。

  堆是所有线程共享的一片公用内存区域。对象都在堆里创建,为了提升效率线程会从堆中弄一个缓存到自己的栈,如果多个线程使用该变量就可能引发问题,这时volatile 变量就可以发挥作用了,它要求线程从主存中读取变量的值。

6.  什么是线程池? 为什么要使用它?

  创建线程要花费资源和时间,如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。为了避免这些问题,在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程。

7. 死锁是什么?如何避免死锁?

  死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足以下四个条件:

1)互斥条件:一个资源每次只能被一个进程使用。

2)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

3)不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。

4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

  避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。

8. Thread类中的yield方法有什么作用?

  Thread.yield() 方法会使当前线程从运行状态变为就绪状态,把运行机会让给其它相同优先级的线程。它是一个静态的原生(native)方法而且只保证当前线程放弃CPU占用而不能保证使其它线程一定能占用CPU,执行yield()的线程有可能会被再次继续执行的。

9. Java中notify 和 notifyAll有什么区别?

  调用notify时,只有一个等待线程会被唤醒而且它不能保证哪个线程会被唤醒,这取决于线程调度器。虽然如果你调用notifyAll方法,那么等待该锁的所有线程都会被唤醒。

10.  Java中interrupted 和 isInterruptedd方法的区别?

  interrupted() 和 isInterrupted()的主要区别是前者会将中断状态清除而后者不会。

  Java多线程的中断机制是用内部标识来实现的,调用Thread.interrupt()来中断一个线程就会设置中断标识为true。当中断线程调用静态方法Thread.interrupted()来检查中断状态时,中断状态会被清零。而非静态方法isInterrupted()用来查询其它线程的中断状态且不会改变中断状态标识。简单的说就是任何抛出InterruptedException异常的方法都会将中断状态清零。无论如何,一个线程的中断状态有有可能被其它线程调用中断来改变。

11. Java多线程中调用wait() 和 sleep()方法有什么不同?

  sleep()和wait()都是使线程暂停执行一段时间的方法。二者区别为:

1)原理不同。

  sleep()方法是Thread类的静态方法,是线程用来控制自身流程的,它会使此线程暂停执行一段时间,而把执行机会让给其他线程,等到计时时间一到,此线程会自动苏醒。而wait()方法是Object类的方法,用于线程间的通信,这个方法会使当前拥有该对象锁的进程等待,直到其他线程用调用notify()或notifyAll()时才苏醒过来,开发人员也可以给它指定一个时间使其自动醒来。

2)对锁的处理机制不同。

  由于sleep()方法的主要作用是让线程暂停一段时间,时间一到则自动恢复,不涉及线程间的通信,因此调用sleep()方法仅仅释放CPU资源或者让当前线程停止执行一段时间,但不会释放锁。而wait()方法则不同,当调用wait()方法后,线程会释放掉它所占用的锁,从而使线程所在对象中的其他synchronized数据可被别的线程使用。

3)使用区域不同。

  wait()方法必须放在同步控制方法或者同步语句块中使用,而sleep方法则可以放在任何地方使用。sleep()方法必须捕获异常,而wait()、notify()、notifyAll()不需要捕获异常。在sleep的过程中,有可能被其他对象调用它的interrupt(),产生InterruptedException异常。

  由于sleep不会释放锁标志,容易导致死锁问题的发生,一般情况下,不推荐使用sleep()方法,而推荐使用wait()方法。

12. 有三个线程T1,T2,T3,怎么确保它们按顺序执行?

在多线程中有多种方法让线程按特定顺序执行,你可以用线程类的join()方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行。为了确保三个线程的顺序你应该先启动最后一个(T3调用T2,T2调用T1),这样T1就会先完成而T3最后完成。

13.  如何创建守护线程?

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

/**
 * @author liao.wenhui
 * @date 2019/7/15 15:13
 */
public class DaemonThread {
    public static void main(String[] args) {
        Thread daemonThread = new Thread(new Runnable() {
            @Override
            public void run() {

            }
        });

        //设置守护线程
        daemonThread.setDaemon(true);
        daemonThread.start();
    }
}

前提知识:

  守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件(百度百科)。

  Java线程分为两类分别为daemon线程(守护线程)和User线程(用户线程),在JVM启动时候会调用main函数,main函数所在的线程是一个用户线程,这个是我们可以看到的线程,其实JVM内部同时还启动了好多守护线程,比如垃圾回收线程。那么守护线程和用户线程有什么区别那?区别之一是当最后一个非守护线程结束时候,JVM会正常退出,而不管当前是否有守护线程,也就是说守护线程是否结束并不影响JVM的退出。言外之意是只要有一个用户线程还没结束正常情况下JVM就不会退出。

14. 什么是线程调度器(Thread Scheduler)和时间分片(Time Slicing)?

  线程调度器是一个操作系统服务,它负责为Runnable状态的线程分配CPU时间。一旦我们创建一个线程并启动它,它的执行便依赖于线程调度器的实现。

  时间分片是指将可用的CPU时间分配给可用的Runnable线程的过程。分配CPU时间可以基于线程优先级或者线程等待的时间。线程调度并不受到Java虚拟机控制,所以由应用程序来控制它是更好的选择(即最好不要让你的程序依赖于线程的优先级)。

15.什么是ThreadLocal?

  ThreadLocal用于创建线程的本地变量,我们知道一个对象的所有线程会共享它的全局变量,所以这些变量不是线程安全的,我们可以使用同步技术。但是当我们不想使用同步的时候,我们可以选择ThreadLocal变量。每个线程都会拥有他们自己的Thread变量,它们可以使用get()/set()方法去获取他们的默认值或者在线程内部改变他们的值。

16.Java线程池中submit() 和 execute()方法有什么区别?

  两个方法都可以向线程池提交任务,execute()方法的返回类型是void,它定义在Executor接口中, 而submit()方法可以返回持有计算结果的Future对象,它定义在ExecutorService接口中,它扩展了Executor接口,其它线程池类像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有这些方法。

17.  Java中Runnable和Callable有什么不同?

  Runnable和Callable都代表那些要在不同的线程中执行的任务。Runnable从JDK1.0开始就有了,Callable是在JDK1.5增加的。它们的主要区别是Callable的 call() 方法可以返回任务执行结果值和抛出异常,而Runnable的run()方法没有这些功能。Callable可以返回装载有计算结果的Future对象。

高并发

1. 什么是FutureTask?

  在Java并发程序中FutureTask表示一个可以取消的异步运算。它有启动和取消运算、查询运算是否完成和取回运算结果等方法。只有当运算完成的时候结果才能取回,如果运算尚未完成get方法将会阻塞。一个FutureTask对象可以对调用了Callable和Runnable的对象进行包装,由于FutureTask也是调用了Runnable接口所以它可以提交给Executor来执行。

原文地址:https://www.cnblogs.com/yang-yutao/p/11553044.html

时间: 2024-11-10 11:03:06

JAVA多线程高并发面试题总结的相关文章

Java多线程并发基础面试题回答

Java多线程面试问题 1. 进程和线程之间有什么不同? 一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用.而线程是在进程中执行的一个任务.Java运行环境是一个包含了不同的类和程序的单一进程.线程可以被称为轻量级进程.线程需要较少的资源来创建和驻留在进程中,并且可以共享进程中的资源. 2. 多线程编程的好处是什么? 在多线程程序中,多个线程被并发的执行以提高程序的效率,CPU不会因为某个线程需要等待资源而进入空闲状态.多个线程共享堆内存(heap

java多线程高并发的学习

1.      计算机系统 使用高速缓存来作为内存与处理器之间的缓冲,将运算需要用到的数据复制到缓存中,让计算能快速进行:当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了. 缓存一致性:多处理器系统中,因为共享同一主内存,当多个处理器的运算任务都设计到同一块内存区域时,将可能导致各自的缓存数据不一致的情况,则同步回主内存时需要遵循一些协议. 乱序执行优化:为了使得处理器内部的运算单位能尽量被充分利用. 2.      JAVA内存模型 目标是定义程序中各个变量的访问规则.

Java名企高频率面试题及答案 精心整理(三)

17.Override和Overload的含义去区别 重写(Override) 重写是子类对父类的允许访问的方法的实现过程进行重新编写!返回值和形参都不能改变.即外壳不变,核心重写! 重写的好处在于子类可以根据需要,定义特定于自己的行为. 也就是说子类能够根据需要实现父类的方法. 在面向对象原则里,重写意味着可以重写任何现有方法.实例如下: class Animal{ public void move(){ System.out.println("动物可以移动"); } } class

Java名企高频率面试题及答案 精心整理(一)

请尊重个人劳动成果,转载注明出处,谢谢! 1 . 九种基本数据类型的大小,以及他们的封装类. 变量就是申请内存来存储值.也就是说,当创建变量的时候,需要在内存中申请空间. 内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类型数据. 因此,通过定义不同类型的变量,可以在内存中储存整数.小数或者字符. Java的两大数据类型: (一).内置数据类型(基本数据类型) 1 六种数字类型 ( byte, short, int, long, float, double) + void

java多线程高并发

旭日Follow_24 的CSDN 博客 ,全文地址请点击: https://blog.csdn.net/xuri24/article/details/81293321 "高并发和多线程"总是被一起提起,给人感觉两者好像相等,实则 高并发 ≠ 多线程 多线程是完成任务的一种方法,高并发是系统运行的一种状态,通过多线程有助于系统承受高并发状态的实现 一,高并发与多线程 1,高并发:高并发不是JAVA的专有的东西,是语言无关的广义的,为提供更好互联网服务而提出的概念.高并发想让服务器(to

java多线程高并发知识总结

1.      计算机系统 使用高速缓存来作为内存与处理器之间的缓冲,将运算需要用到的数据复制到缓存中,让计算能快速进行:当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了. 缓存一致性:多处理器系统中,因为共享同一主内存,当多个处理器的运算任务都设计到同一块内存区域时,将可能导致各自的缓存数据不一致的情况,则同步回主内存时需要遵循一些协议. 乱序执行优化:为了使得处理器内部的运算单位能尽量被充分利用. 2.      JAVA内存模型 目标是定义程序中各个变量的访问规则.

Java名企高频率面试题及答案 精心整理(二)

11.HashMap和ConcurrentHashMap的区别,HashMap的底层源码 Hashmap本质是数组加链表.根据key取得hash值,然后计算出数组下标,如果多个key对应到同一个下标,就用链表串起来,新插入的在前面. ConcurrentHashMap:在hashMap的基础上,ConcurrentHashMap将数据分为多个segment(类似hashtable),默认16个(concurrency level),然后在每一个分段上都用锁进行保护,从而让锁的粒度更精细一些,并发

Java多线程高并发学习笔记(三)——深入理解线程池

线程池最核心的一个类:ThreadPoolExecutor. 看一下该类的构造器: public ThreadPoolExecutor(int paramInt1, int paramInt2, long paramLong, TimeUnit paramTimeUnit, BlockingQueue<Runnable> paramBlockingQueue) { this(paramInt1, paramInt2, paramLong, paramTimeUnit, paramBlockin

50个Java多线程面试题

不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java 语言一个重要的特点就是内置了对并发的支持,让 Java 大受企业和程序员的欢迎.大多数待遇丰厚的 Java 开发职位都要求开发者精通多线程技术并且有丰富的 Java 程序开发.调试.优化经验,所以线程相关的问题在面试中经常会被提到. 在典型的 Java 面试中, 面试官会从线程的基本概念问起, 如:为什么你需要使用线程, 如何创建线程,用什么方式创建线程比较好(比如:继承 thread 类还是调用 Runnable 接口),