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

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

29. Java中的wait()和sleep()方法之间有什么区别?

等待():

  • wait()方法释放锁定。
  • wait()是Object类的方法。
  • wait()是非静态方法–公共最终void wait()引发InterruptedException {//…}
  • 应该通过notify()或notifyAll()方法通知wait()。
  • 需要从循环中调用wait()方法以处理错误警报。
  • 必须从同步上下文(即同步方法或块)中调用wait()方法,否则它将引发IllegalMonitorStateException

sleep():

  • sleep()方法不会释放锁。
  • sleep()是java.lang.Thread类的方法。
  • sleep()是静态方法–公共静态无效睡眠(长毫秒,int nanos)抛出InterruptedException {//…}
  • 在指定的时间后,sleep()完成。
  • sleep()最好不要从循环中调用(即参见下面的代码)。
  • sleep()可以从任何地方调用。没有具体要求。

30.当未捕获的异常离开run()方法时会发生什么

我可能碰巧一个未经检查的异常从run()方法中逃逸了在这种情况下,线程由Java虚拟机停止。通过将实现接口的实例注册UncaughtExceptionHandler为异常处理程序,可以捕获此异常

这可以通过调用static方法来完成,该方法Thread.setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler)告诉JVM在线程自身上没有注册任何特定的处理程序的情况下使用提供的处理程序,或者通过setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler)在线程实例本身上进行调用

31.两个接口Runnable

Callable?

接口Runnable定义了run()没有任何返回值Callable的方法call()而接口则允许方法返回值并抛出异常。

32.什么是关机钩?

关闭钩子是在JVM关闭时执行的线程。可以通过addShutdownHook(Runnable)在Runtime实例上调用来注册它

Runtime.getRuntime().addShutdownHook(new Thread() {
    @Override
    public void run() {
    }
});

2.2通过sleep暂停执行

33.如何防止繁忙的等待?

防止繁忙等待的一种方法是使当前线程在给定的时间内休眠。这可以java.lang.Thread.sleep(long)通过传递方法将进入睡眠的毫秒数作为参数来调用该方法来完成

34.我们可以Thread.sleep()用于实时处理吗?

传递给的毫秒数Thread.sleep(long)仅表示调度程序不需要当前线程执行多长时间。根据实际的实现,调度程序可能会让线程提前或延迟几毫秒再执行一次。因此,Thread.sleep()不应将的调用用于实时处理。

35.该方法Thread.yield()做什么?

静态方法的调用为Thread.yield()调度程序提供了一个提示,即当前线程愿意释放处理器。调度程序可以随意忽略此提示。由于未定义调用哪个线程将获得处理器Thread.yield(),因此甚至有可能当前线程成为要执行的“下一个”线程。

36.该类有哪些用例java.util.concurrent.Future

该类的实例java.util.concurrent.Future用于表示异步计算的结果,这些结果无法立即获得。因此,该类提供了一些方法来检查异步计算是否已完成,取消任务并检索实际结果。后者可以通过提供的两种get()方法来完成第一个get()方法不带参数,并阻塞直到结果可用为止;第二个get()方法带一个超时参数,如果结果在给定的时间范围内不可用,则该超时参数使方法调用返回。

37.我们如何在Java中停止线程?

要停止线程,可以使用指向当前线程的易失性引用,该引用可以被其他线程设置为null,以指示当前线程应停止其执行:

private static class MyStopThread extends Thread {
    private volatile Thread stopIndicator;
    public void start() {
        stopIndicator = new Thread(this);
        stopIndicator.start();
    }
    public void stopThread() {
        stopIndicator = null;
    }
    @Override
    public void run() {
        Thread thisThread = Thread.currentThread();
        while(thisThread == stopIndicator) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
        }
    }
}

2.3中断

38.如何唤醒使用前已进入睡眠状态的线程Thread.sleep()

该方法interrupt()java.lang.Thread中断睡眠线程。已通过调用进入睡眠状态的中断线程Thread.sleep()被唤醒InterruptedException

public class InterruptExample implements Runnable {
    public void run() {
        try {
            Thread.sleep(Long.MAX_VALUE);
        } catch (InterruptedException e) {
            System.out.println("["+Thread.currentThread().getName()+"] Interrupted by exception!");
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread myThread = new Thread(new InterruptExample(), "myThread");
        myThread.start();
        System.out.println("["+Thread.currentThread().getName()+"] Sleeping in main thread for 5s...");
        Thread.sleep(5000);
        System.out.println("["+Thread.currentThread().getName()+"] Interrupting myThread");
        myThread.interrupt();
    }
}

39.线程如何查询是否已被中断?

如果线程不在Thread.sleep()抛出的方法之内InterruptedException,则该线程可以通过调用静态方法Thread.interrupted()isInterrupted()从其继承的方法来查询是否已被中断java.lang.Thread.

40.应该如何InterruptedException处理?

sleep()join()抛出这样的方法InterruptedException告诉调用者另一个线程已中断该线程。在大多数情况下,这样做是为了告诉当前线程停止其当前计算并意外完成它们。因此,通过捕获异常并仅将其记录到控制台或某些日志文件中来忽略该异常通常不是处理此类异常的适当方法。此异常的问题在于,run()Runnable接口的方法不允许run()抛出任何异常。因此,仅将其重新添加无济于事。这意味着的实现run()必须自己处理此检查的异常,这通常会导致其被捕获和忽略的事实。


2.4加入

41.在启动子线程之后,我们如何在父线程中等待子线程的终止?

通过调用join()线程的实例变量上的方法等待线程终止

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
    }
});
thread.start();
thread.join();

42.以下程序的输出是什么?

上面的代码的输出为“ false”。尽管MyDaemonThread的实例是守护程序线程,但是的调用join()会使主线程等待,直到守护程序线程的执行完成。因此,调用isAlive()线程实例显示守护程序线程不再运行。

3.同步

43.同步方法和同步块之间的区别?

  • 同步块减小了锁定范围,但是同步方法的锁定范围是整个方法。
  • 同步块的性能更好,因为只有关键部分被锁定,但是同步方法的性能比块差。
  • 同步块提供了对锁的精细控制,但对此对象或类级别锁表示的当前对象提供了同步方法锁。
  • 同步块可以抛出NullPointerException,但同步方法不会抛出。
  • 同步块:同步(此){}
  • 同步方法:公共同步void fun(){}

44.什么是Java中的volatile关键字,它与Java中的同步方法有何不同?

使用volatile强制线程直接从RAM存储器读取和写入变量。因此,当许多线程都使用相同的volatile变量时,它们都将看到RAM内存中存在的最新版本,而不是高速缓存中可能的旧副本。当线程进入同步块时,它需要控制监视变量。所有其他线程等待,直到第一个线程从同步块退出。为了确保所有线程都能看到相同的修改,同步块中使用的所有变量都直接从RAM内存而不是从缓存副本读取和写入。

45.同步关键字用于什么目的?

当您必须实现对资源的互斥访问(例如某些静态值或某些文件引用)时,可以使用同步块包含与互斥资源一起使用的代码:

synchronized (SynchronizedCounter.class) {
    counter++;
}

46.什么是信号量?

信号量是一种数据结构,它维护一组必须由竞争线程获取的许可。因此,信号量可用于控制有多少线程同时访问关键部分或资源。因此,的构造函数java.util.concurrent.Semaphore将线程竞争的许可数量作为第一个参数。每次调用其acquire()方法都会尝试获取可用许可之一。acquire()在下一个允许获得可用之前,没有任何参数块的方法稍后,当线程完成对关键资源的工作时,它可以通过release()在Semaphore实例上调用该方法来释放许可

47.什么是CountDownLatch

SDK类CountDownLatch提供了一个同步辅助工具,可用于实现以下场景:线程必须等待,直到其他一些线程达到相同状态才能启动所有线程。通过提供一个递减的同步计数器,直到其达到零值,即可完成此操作。CountDownLatch实例达到零后,将允许所有线程继续进行。可以使用计数器的值1来让所有线程在给定的时间点启动,也可以等待直到多个线程完成。在后一种情况下,计数器将使用线程数进行初始化,并且每个完成其工作的线程都会将锁存器递减一个。

48. aCountDownLatch和a有CyclicBarrier什么区别

这两个SDK类都在内部维护一个计数器,该计数器由不同的线程递减。线程等待直到内部计数器达到零值,然后从那里继续。但是与CountDownLatch相反,该类CyclicBarrier将值重置为零后将内部值重置为初始值。顾名思义,CyclicBarrier因此的实例可用于实现用例,其中线程必须一次又一次地等待彼此。

3.1内部锁和同步

49.同步方法获得什么内在锁?

同步方法获取该方法对象的固有锁定,并在方法返回时释放该锁定。即使该方法引发异常,也将释放固有锁定。因此,同步方法等于以下代码:

public void method() {
    synchronized(this) {
        ...
    }
}

50.如果两个线程同时在不同的对象实例上调用同步方法,这些线程之一会阻塞吗?

两种方法都锁定同一监视器。因此,您不能同时在不同线程上的同一对象上执行它们(两种方法之一将阻塞,直到另一种方法完成)。

51.构造函数可以同步吗?

否,构造函数无法同步。之所以导致语法错误,是因为只有构造线程才有权访问正在构造的对象。

52. Lock与同步相比有什么好处?

锁的优点是:

  • 有可能使它们公平
  • 在等待Lock对象时,可以使线程响应中断。
  • 可以尝试获取锁,但是如果无法获取锁,则立即返回或在超时后返回
  • 可以在不同的范围内以不同的顺序获取和释放锁

53.原始值可以用于内部锁吗?

不可以,原始值不能用于内部锁。

54.内在锁是否可重入?

是的,同一线程可以一次又一次地访问固有锁。否则,获取锁的代码将必须注意,它不会偶然尝试获取已获取的锁。

55.我们对公平锁有什么了解?

选择是通过障碍的一些独家资源的下一个线程时,一个公平的锁占用线程的等待时间考虑在内。公平锁的示例实现由Java SDK提供:java.util.concurrent.locks.ReentrantLock如果使用布尔标志设置为true的构造函数,则ReentrantLock授予对等待时间最长的线程的访问权限。

56. SDK类ReadWriteLock使用了哪种减少锁争用的技术?

SDK类ReadWriteLock使用以下事实:并发线程在没有其他线程尝试更新值的情况下想要读取值时不必获取锁。这由一对锁实现,一个锁用于只读操作,一个锁用于写操作。尽管可以通过多个线程获得只读锁,但是该实现保证释放写锁后,所有读取操作都将看到更新的值。

3.2原子访问

57.我们通过原子操作了解什么?

原子操作是完全执行或根本不执行的操作。

58.语句c ++是原子的吗?

不,一个整数变量的增量包括一个以上的运算。首先,我们必须加载c的当前值,将其递增,然后最后将新值存储回去。执行此增量的当前线程可能会在这三个步骤中的任何一个之间中断,因此此操作不是原子操作。

59. Java中哪些操作是原子操作?

Java语言提供了一些原子性的基本操作,因此可用于确保并发线程始终看到相同的值:

  • 对参考变量和原始变量(长整型和双精度型除外)的读写操作
  • 对声明为易失性的所有变量的读写操作

4.活泼

4.1死锁

60.我们对僵局有什么了解?

死锁是一种情况,其中两个(或更多)线程各自在另一个线程上等待以释放其已锁定的资源,而线程本身已锁定另一个线程在等待的资源:

  • 线程1:锁定资源A,等待资源B
  • 线程2:锁定资源B,等待资源A

61.僵局情况有哪些要求?

通常,可以确定以下死锁要求:

  • 互斥:有一种资源在任何时间点只能由一个线程访问。
  • 资源持有:锁定一个资源后,线程尝试获取对某个其他排他资源的另一个锁定。
  • 无抢占:没有机制,如果一个线程在特定时间段内持有锁,则该机制可以释放资源。
  • 循环等待:在运行时发生一个星座,其中两个(或更多)线程分别在另一个线程上等待以释放已锁定的资源。

62.完全可以防止死锁吗?

为了防止死锁,必须消除一个或多个死锁的要求:

  • 互斥:在某些情况下,可以通过使用乐观锁定来防止互斥。
  • 资源持有:线程无法成功获取所有排他锁时,可能会释放其所有排他锁。
  • 无抢占:对独占锁使用超时将在给定时间后释放锁。
  • 循环等待:当所有线程以相同顺序获得所有排他锁时,不会发生循环等待。

63.是否可以实现死锁检测?

当监视所有排他锁并将其建模为有向图时,死锁检测系统可以搜索两个线程,每个线程都在等待另一个线程以释放已锁定的资源。然后可以通过某种异常强制等待线程释放另一个线程正在等待的锁。

4.2饥饿和活锁

64.什么是活锁?

活锁是这样的情况,其中两个或更多线程通过响应另一个线程引起的动作而相互阻塞。与死锁情况相反,死锁情况是两个或多个线程在一个特定状态下等待,而参与活动锁的线程则以防止其正常工作进展的方式更改其状态。一个示例是这样一种情况,其中两个线程尝试获取两个锁,但是在无法获取第二个锁时释放它们获取的锁。现在可能会发生,两个线程同时尝试获取第一个线程。由于只有一个线程成功,因此第二线程可以成功获取第二锁。现在,两个线程都持有两个不同的锁,但是由于两个线程都想要拥有两个锁,因此它们释放其锁并从头开始尝试。现在可能一次又一次地发生这种情况。

65.通过线程饥饿我们了解什么?

具有较低优先级的线程比具有较高优先级的线程获得的执行时间更少。当具有较低优先级的线程执行长时间的持久计算时,可能会发生这些线程没有足够的时间及时完成其计算的情况。它们似乎“饿死了”,因为具有更高优先级的线程会占用它们的计算时间。

目录
相关文章
|
5天前
|
存储 缓存 Oracle
Java I/O流面试之道
NIO的出现在于提高IO的速度,它相比传统的输入/输出流速度更快。NIO通过管道Channel和缓冲器Buffer来处理数据,可以把管道当成一个矿藏,缓冲器就是矿藏里的卡车。程序通过管道里的缓冲器进行数据交互,而不直接处理数据。程序要么从缓冲器获取数据,要么输入数据到缓冲器。
Java I/O流面试之道
|
2天前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
15 4
|
2天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
26 4
|
4天前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####
|
26天前
|
存储 安全 算法
Java面试题之Java集合面试题 50道(带答案)
这篇文章提供了50道Java集合框架的面试题及其答案,涵盖了集合的基础知识、底层数据结构、不同集合类的特点和用法,以及一些高级主题如并发集合的使用。
77 1
Java面试题之Java集合面试题 50道(带答案)
|
8天前
|
Java 数据库连接 数据库
如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面
本文介绍了如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面。通过合理配置初始连接数、最大连接数和空闲连接超时时间,确保系统性能和稳定性。文章还探讨了同步阻塞、异步回调和信号量等并发控制策略,并提供了异常处理的最佳实践。最后,给出了一个简单的连接池示例代码,并推荐使用成熟的连接池框架(如HikariCP、C3P0)以简化开发。
22 2
|
15天前
|
存储 Java 程序员
Java面试加分点!一文读懂HashMap底层实现与扩容机制
本文详细解析了Java中经典的HashMap数据结构,包括其底层实现、扩容机制、put和查找过程、哈希函数以及JDK 1.7与1.8的差异。通过数组、链表和红黑树的组合,HashMap实现了高效的键值对存储与检索。文章还介绍了HashMap在不同版本中的优化,帮助读者更好地理解和应用这一重要工具。
35 5
|
14天前
|
存储 Java
[Java]面试官:你对异常处理了解多少,例如,finally中可以有return吗?
本文介绍了Java中`try...catch...finally`语句的使用细节及返回值问题,并探讨了JDK1.7引入的`try...with...resources`新特性,强调了异常处理机制及资源自动关闭的优势。
16 1
|
23天前
|
Java 程序员
Java 面试高频考点:static 和 final 深度剖析
本文介绍了 Java 中的 `static` 和 `final` 关键字。`static` 修饰的属性和方法属于类而非对象,所有实例共享;`final` 用于变量、方法和类,确保其不可修改或继承。两者结合可用于定义常量。文章通过具体示例详细解析了它们的用法和应用场景。
24 3
|
25天前
|
Java
【编程进阶知识】揭秘Java多线程:并发与顺序编程的奥秘
本文介绍了Java多线程编程的基础,通过对比顺序执行和并发执行的方式,展示了如何使用`run`方法和`start`方法来控制线程的执行模式。文章通过具体示例详细解析了两者的异同及应用场景,帮助读者更好地理解和运用多线程技术。
25 1