收下这一波2021年,最新的,Java并发面试题(上)

简介: 收下这一波2021年,最新的,Java并发面试题

1.进程和线程

1.我们对“并发”一词有什么了解?

并发是程序同时执行多个计算的能力。这可以通过将计算分布在计算机的可用CPU内核上,甚至在同一网络内的不同计算机上来实现。

2.进程和线程之间有什么区别?

进程是操作系统提供的执行环境,它具有自己的一组私有资源(例如,内存,打开的文件等)。与流程相反,线程位于流程内,并与流程的其他线程共享资源(内存,打开的文件等)。在不同线程之间共享资源的能力使线程更适合于对性能有重要要求的任务。

3.在Java中,什么是进程和线程?

在Java中,进程对应于正在运行的Java虚拟机(JVM),而线程位于JVM中,并且可以由Java应用程序在运行时动态创建和停止。

4.什么是调度程序?

调度程序是一种调度算法的实现,该算法管理进程和线程对某些有限资源(如处理器或某些I / O通道)的访问。大多数调度算法的目标是为可用的进程/线程提供某种负载平衡,以确保每个进程/线程都有适当的时间范围以排他地访问所请求的资源。

5. Java程序至少具有多少个线程?

每个Java程序都在主线程中执行;因此,每个Java应用程序都有至少一个线程。

6. Java应用程序如何访问当前线程?

可以通过调用currentThread()JDK类的静态方法来访问当前线程java.lang.Thread

public class MainThread {
    public static void main(String[] args) {
        long id = Thread.currentThread().getId();
        String name = Thread.currentThread().getName();
        ..
    }
}

7.每个Java线程都有哪些属性?

每个Java线程都具有以下属性:

  • 在JVM中唯一的long类型的标识符
  • 类型为String的名称
  • int类型的优先级
  • 类型状态 java.lang.Thread.State
  • 线程所属的线程组

8.线程组的目的是什么?

每个线程都属于一组线程。JDK类java.lang.ThreadGroup提供了一些方法来处理整个线程组。使用这些方法,例如,我们可以中断组中的所有线程或设置其最大优先级。

9.线程可以具有哪些状态,每个状态的含义是什么?

  • NEW: 尚未启动的线程处于此状态。
  • RUNNABLE: 在Java虚拟机中执行的线程处于这种状态。
  • BLOCKED: 等待监视器锁定而被阻塞的线程处于此状态。
  • WAITING: 无限期地等待另一个线程执行特定操作的线程处于此状态。
  • TIMED_WAITING: 正在等待另一个线程执行操作的线程最多达到指定的等待时间,该线程处于此状态。
  • TERMINATED: 退出的线程处于此状态。

10.多线程编程的好处是什么?

多线程代码可以在以下方面提供帮助:

  • 改善应用程序响应能力
  • 有效地使用多处理器
  • 改善计划结构
  • 使用更少的系统资源

11.在多线程环境中遇到哪些常见问题?

  • 僵局–两个线程A和B分别持有lock_A和lock_B。他们两个都希望访问资源R。为了安全地访问R,需要lock_A和lock_B。但是线程A需要lock_B,线程B需要lock_A。但是他们两个都不准备放弃他们持有的锁。因此,没有任何进展。陷入僵局!
  • 种族条件–考虑生产者-消费者的经典例子。如果您在添加或从队列中删除项目之前忘记锁定该怎么办?想象一下,两个线程A和B试图在不锁定的情况下添加项目。线程A访问队列的后面。然后,调度程序就有机会运行线程B,该线程B成功添加了项并更新了尾指针。现在,线程A读取的尾指针已过时,但它认为它是尾并添加了该项。因此,B添加的项目是LOST!数据结构已损坏!更糟糕的是,清理时还可能导致内存泄漏。
  • 数据竞争–想象应该设置的标志变量。假设您已锁定以避免比赛条件。现在,不同的线程想要设置不同的值。由于调度程序可以以任何方式调度线程执行,因此您最终不知道标志的值。
  • 饥饿–这是线程调度程序引起的问题。一些线程没有机会运行和完成,或者无法获得所需的锁,因为其他线程被赋予了更高的优先级。他们“饿死”了CPU周期或其他资源。
  • 优先级反转–想象两个线程A和B。A具有比B高的优先级,因此比B具有更多的CPU周期。但是在访问共享资源时,B持有A所需的锁并屈服。现在,如果没有锁,A无法做任何事情,并且浪费了大量CPU周期,因为B没有获得足够的周期,但是拥有了锁。

12.我们如何设置线程的优先级?

使用方法可以设置线程的优先级setPriority(int)要将优先级设置为最大值,我们使用常量Thread.MAX_PRIORITY,将其设置为最小值,我们使用常量,Thread.MIN_PRIORITY因为这些值在不同的JVM实现之间可能会有所不同。

13.什么是多线程中的上下文切换?

纯粹的多任务处理不存在。同时执行两项具有挑战性的任务是不可能的。因此,当我们执行多任务时,我们真正要做的就是不断地从一项任务切换到另一项任务。这就是上下文切换。

该术语起源于计算机科学。但是,它同样适用于人类执行的心理任务。毕竟,人类的思想在许多方面都类似于CPU。

就像运行多线程进程的CPU在运行另一个线程时暂时搁置一个给定线程的执行一样,人类的大脑也搁置一个任务以将其重点转移到另一个任务上。

14. Java中的绿色线程和本地线程之间的区别?

  • 绿色线程是指Java虚拟机本身在一个操作系统进程中创建,管理和上下文切换所有Java线程的模型。没有使用操作系统线程库。
  • 本机线程是指Java虚拟机使用操作系统线程库(在UnixWare上名为libthread)创建和管理Java线程,并且每个Java线程都映射到一个线程库线程。

15.我们对种族条件一词有什么了解?

竞争条件描述的星座图,其中某些多线程实现的结果取决于参与线程的确切计时行为。在大多数情况下,具有这种行为是不希望的,因此,竞赛条件一词还意味着由于缺少线程同步而导致的错误会导致不同的结果。竞争条件的一个简单示例是两个并行线程对整数变量的递增。由于该操作由一个以上的单个原子操作组成,因此可能发生两个线程读取并增加相同值的情况。在此并发增量之后,整数变量的数量不会增加2,而只会增加1

16.将对象实例从一个线程传递到另一个线程时,您需要考虑什么?

在线程之间传递对象时,必须注意这些对象不能同时由两个线程操纵。一个示例是一个Map实现,其键/值对由两个并发线程修改。为了避免并发修改出现问题,可以将对象设计为不可变的。

17.是否可以通过使用多线程来提高应用程序的性能?列举一些例子。

如果我们有多个CPU内核可用,并且可以在可用的CPU内核上并行化计算,则可以通过多线程来提高应用程序的性能。一个示例是应该缩放存储在本地目录结构中的所有图像的应用程序。生产者/消费者实现可以使用一个线程扫描目录结构和执行实际缩放操作的一堆工作线程,而不是一个接一个地遍历所有图像。另一个示例是镜像某些网页的应用程序。生产者线程可以解析第一个HTML页面并将发现的链接发布到队列中,而不是先加载一个HTML页面。工作线程监视队列并加载解析器找到的网页。

18.我们对可扩展性一词有什么了解?

可伸缩性是指程序通过向其添加更多资源来提高性能的能力。

19.是否可以通过使用多个处理器来计算应用程序的理论最大速度?

通过为应用程序提供多个处理器,阿姆达尔定律提供了一个计算理论上最大速度的公式。理论上的加速由S(n) = 1 / (B + (1-B)/n)下式计算:其中n表示处理器数量和B无法并行执行的程序部分。当n收敛于无穷大时,项(1-B)/n收敛于零。因此,在这种特殊情况下,公式可以简化为1/B正如我们所看到的,理论上最大加速比是必须依次执行的分数的倒数。这意味着该分数越低,可以实现越多的理论加速。

20.提供一个示例,说明为什么单线程应用程序的性能改进会导致多线程应用程序的性能下降。

此类优化的一个突出示例是将List元素数量保持为单独变量的实现。由于该size()操作不必遍历所有元素,而是可以直接返回当前数量的元素,因此可以提高单线程应用程序的性能在多线程应用程序中,由于多个并发线程可能会将元素插入列表,因此必须通过锁来保护其他计数器。当列表的更新次数超过size()操作的调用次数时,此附加锁定可能会降低性能

2.线程对象

2.1定义和启动线程

21.如何用Java创建线程?

基本上,有两种方法可以用Java创建线程。

第一个是编写一个扩展JDK类java.lang.Thread并调用其方法的start()

public class MyThread extends Thread {
   public MyThread(String name) {
        super(name);
    }
    @Override
    public void run() {
        System.out.println("Executing thread "+Thread.currentThread().getName());
    }
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread("myThread");
        myThread.start();
    }
}

第二种方法是实现接口java.lang.Runnable,并将此实现作为参数传递给的构造函数java.lang.Thread

public class MyRunnable implements Runnable {
    public void run() {
        System.out.println("Executing thread "+Thread.currentThread().getName());
    }
    public static void main(String[] args) throws InterruptedException {
        Thread myThread = new Thread(new MyRunnable(), "myRunnable");
        myThread.start();
    }
}

22.为什么不应该通过调用其方法来停止线程stop()

线程不应该被使用过时的方法来停止stop()java.lang.Thread,因为该方法的调用导致线程解锁已获取所有的显示器。如果受释放锁之一保护的任何对象处于不一致状态,则此状态对所有其他线程可见。当其他线程对此不一致的对象进行处理时,这可能导致任意行为。

23.是否可以启动一个线程两次?

否,在通过调用线程的start()方法启动线程之后,第二次调用start()将抛出IllegalThreadStateException

24.以下代码的输出是什么?

public class MultiThreading {
    private static class MyThread extends Thread {
        public MyThread(String name) {
            super(name);
        }
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName());
        }
    }
   public static void main(String[] args) {
        MyThread myThread = new MyThread("myThread");
        myThread.run();
    }
}

上面的代码产生输出“ main”而不是“ myThread”。从该main()方法的第二行可以看出,我们错误地调用run()而不是方法start()因此,没有启动新线程,但是该方法run()在主线程中执行。

25.什么是守护线程?

守护程序线程是当JVM决定是否应该停止时,不评估其执行状态的线程。当所有用户线程(与守护程序线程相反)终止时,JVM停止。因此,一旦所有用户线程停止,守护程序线程就可以用于实现监视功能,例如,JVM停止了该线程:

public class Example {
    private static class MyDaemonThread extends Thread {
        public MyDaemonThread() {
            setDaemon(true);
        }
        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new MyDaemonThread();
        thread.start();
    }
}

即使守护线程仍在其无尽的while循环中运行,以上示例应用程序也会终止。

26.什么是Java线程转储?

Java线程转储是一种找出JVM中每个线程在特定时间点正在做什么的方法。

如果您的Java应用程序有时在负载下运行时挂起,这将特别有用,因为对转储的分析将显示线程卡在哪里。

您可以在Unix / Linux下通过运行kill -QUIT <pid>来生成线程转储,而在Windows下则可以通过按Ctl + Break来生成线程转储。

27.是否可以在启动普通用户线程后将其转换为守护线程?

用户线程一旦启动就无法转换为守护线程。thread.setDaemon(true)在已经运行的线程实例上调用该方法会导致IllegalThreadStateException

28.忙碌等待使我们了解什么?

繁忙等待是指通过执行一些活动计算来等待事件的实现,这些计算使线程/进程占用了处理器,尽管调度程序可以将其从处理器中删除。繁忙等待的一个示例是将等待时间花费在一个循环中,该循环一次又一次地确定当前时间,直到到达某个时间点为止:

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        long millisToStop = System.currentTimeMillis() + 5000;
        long currentTimeMillis = System.currentTimeMillis();
        while (millisToStop > currentTimeMillis) {
            currentTimeMillis = System.currentTimeMillis();
        }
    }
});
目录
相关文章
|
6天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
12天前
|
存储 缓存 Oracle
Java I/O流面试之道
NIO的出现在于提高IO的速度,它相比传统的输入/输出流速度更快。NIO通过管道Channel和缓冲器Buffer来处理数据,可以把管道当成一个矿藏,缓冲器就是矿藏里的卡车。程序通过管道里的缓冲器进行数据交互,而不直接处理数据。程序要么从缓冲器获取数据,要么输入数据到缓冲器。
Java I/O流面试之道
|
1天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
10 2
|
8天前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
28 4
|
9天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
42 4
|
10天前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####
|
1月前
|
存储 安全 算法
Java面试题之Java集合面试题 50道(带答案)
这篇文章提供了50道Java集合框架的面试题及其答案,涵盖了集合的基础知识、底层数据结构、不同集合类的特点和用法,以及一些高级主题如并发集合的使用。
81 1
Java面试题之Java集合面试题 50道(带答案)
|
15天前
|
Java 数据库连接 数据库
如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面
本文介绍了如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面。通过合理配置初始连接数、最大连接数和空闲连接超时时间,确保系统性能和稳定性。文章还探讨了同步阻塞、异步回调和信号量等并发控制策略,并提供了异常处理的最佳实践。最后,给出了一个简单的连接池示例代码,并推荐使用成熟的连接池框架(如HikariCP、C3P0)以简化开发。
33 2
|
21天前
|
存储 Java 程序员
Java面试加分点!一文读懂HashMap底层实现与扩容机制
本文详细解析了Java中经典的HashMap数据结构,包括其底层实现、扩容机制、put和查找过程、哈希函数以及JDK 1.7与1.8的差异。通过数组、链表和红黑树的组合,HashMap实现了高效的键值对存储与检索。文章还介绍了HashMap在不同版本中的优化,帮助读者更好地理解和应用这一重要工具。
45 5
|
20天前
|
存储 Java
[Java]面试官:你对异常处理了解多少,例如,finally中可以有return吗?
本文介绍了Java中`try...catch...finally`语句的使用细节及返回值问题,并探讨了JDK1.7引入的`try...with...resources`新特性,强调了异常处理机制及资源自动关闭的优势。
18 1