热门关键字: 6070 111 11 11 11 11
归纳概括 文章 文章写作 贯彻执行题 
  面试题及答案 深入解析Java线程Dump:DestroyJavaVM线程状态与优先级详解
发表评论 来源:网络整理 编辑:admin2 日期:2024-12-16

FullthreaddumpJavaHotSpot(TM)64-BitServerVM(25.144-b01mixedmode):

/*线程名称:DestroyJavaVM

编号:#13

优先级:5

系统优先级:0

jvm内部线程ID:0x0000000001c88800

对应的系统线程id(NativeThreadID):0x1c18

线程状态: waitingoncondition[0x00000](等待某个条件)

线程详细状态:java.lang.Thread.State:RUNNABLE 及之后的所有 */

“销毁JavaVM”#13prio=5os_prio=0tid=0x0000000001c88800nid=0x1c18waitingoncondition[0x00000]

java.lang.Thread.State:RUNNABLE

“Thread-1”#12prio=5os_prio=0tid=0x0000000018d49000nid=0x17b8waitingformonitorentry[0x0000000019d7f000]

/*线程状态:阻塞(对象同步时)

代码位置:atcom.leo.interview.SimpleDeadLock$B.run(SimpleDeadLock.java:56)

等待锁定:0x00000000d629b4d8

获得锁:0x00000000d629b4e8*/

java.lang.Thread.State:BLOCKED(onobjectmonitor)

atcom.leo.interview.SimpleDeadLock$B.run(SimpleDeadLock.java:56)

-waitingtolock(ajava.lang.Object)

-locked(ajava.lang.Object)

“线程0”#11prio=5os_prio=0tid=0x0000000018d44000nid=0x1ebcwaitingformonitorentry[0x7f000]

java.lang.Thread.State:BLOCKED(onobjectmonitor)

atcom.leo.interview.SimpleDeadLock$A.run(SimpleDeadLock.java:34)

-waitingtolock(ajava.lang.Object)

-locked(ajava.lang.Object)

“ServiceThread”#10daemonprio=9os_prio=0tid=0x0000000018ca5000nid=0x1264runnable[0x00000]

java.lang.Thread.State:RUNNABLE

"C1CompilerThread2"#9daemonprio=9os_prio=2tid=0x0000000018c46000nid=0xb8cwaitingoncondition[0x00000]

java.lang.Thread.State:RUNNABLE

“C2CompilerThread1”#8daemonprio=9os_prio=2tid=0x0000000018be4800nid=0x1db4waitingoncondition[0x00000]

java.lang.Thread.State:RUNNABLE

“C2CompilerThread0”#7daemonprio=9os_prio=2tid=0x0000000018be3800nid=0x810waitingoncondition[0x00000]

java.lang.Thread.State:RUNNABLE

“MonitorCtrl-Break”#6daemonprio=5os_prio=0tid=0x0000000018bcc800nid=0x1c24runnable[0xce000]

java.lang.Thread.State:RUNNABLE

.SocketInputStream.socketRead0(NativeMethod)

.SocketInputStream.socketRead(SocketInputStream.java:116)

.SocketInputStream.read(SocketInputStream.java:171)

.SocketInputStream.read(SocketInputStream.java:141)

atsun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)

atsun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)

atsun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)

-locked(ajava.io.InputStreamReader)

atjava.io.InputStreamReader.read(InputStreamReader.java:184)

atjava.io.BufferedReader.fill(BufferedReader.java:161)

atjava.io.BufferedReader.readLine(BufferedReader.java:324)

-locked(ajava.io.InputStreamReader)

atjava.io.BufferedReader.readLine(BufferedReader.java:389)

atcom.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64)

“AttachListener”#5daemonprio=5os_prio=2tid=0x81800nid=0x524runnable[0x00000]

java.lang.Thread.State:RUNNABLE

“SignalDispatcher”#4daemonprio=9os_prio=2tid=0x8f800nid=0x1b08waitingoncondition[0x00000]

java.lang.Thread.State:RUNNABLE

“终结器”#3daemonprio=8os_prio=1tid=0x6a800nid=0xdacinObject.wait()[0x0000000018b6f000]

java.lang.Thread.State:WAITING(onobjectmonitor)

atjava.lang.Object.wait(NativeMethod)

-waitingon(ajava.lang.ref.ReferenceQueue$Lock)

atjava.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)

-locked(ajava.lang.ref.ReferenceQueue$Lock)

atjava.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)

atjava.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

“ReferenceHandler”#2daemonprio=10os_prio=2tid=0x23800nid=0x1670inObject.wait()[0xef000]

java.lang.Thread.State:WAITING(onobjectmonitor)

atjava.lang.Object.wait(NativeMethod)

-waitingon(ajava.lang.ref.Reference$Lock)

atjava.lang.Object.wait(Object.java:502)

atjava.lang.ref.Reference.tryHandlePending(Reference.java:191)

-locked(ajava.lang.ref.Reference$Lock)

atjava.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

“VMThread”os_prio=2tid=0x1b800nid=0x604runnable

“GCtaskthread#0(并行GC)”os_prio=0tid=0x0000000001c9d800nid=0x9f0runnable

“GCtaskthread#1(并行GC)”os_prio=0tid=0x0000000001c9f000nid=0x154crunnable

“GCtaskthread#2(并行GC)”os_prio=0tid=0x0000000001ca0800nid=0xcd0runnable

“GCtaskthread#3(并行GC)”os_prio=0tid=0x0000000001ca2000nid=0x1e58runnable

“VMPeriodicTaskThread”os_prio=2tid=0x0000000018c5a000nid=0x1b58waitingoncondition

JNI全局参考:33

/*这里可以查看死锁的信息! */

发现一个Java级别的死锁:

=============================

“线程1”:

waitingtolockmonitor0x29fc8(object0x00000000d629b4d8,ajava.lang.Object),

由“Thread-0”持有

“线程-0”:

waitingtolockmonitor0x27738(object0x00000000d629b4e8,ajava.lang.Object),

由“Thread-1”持有

上面列出的线程的 Java 堆栈信息:

=================================================== =

“线程1”:

atcom.leo.interview.SimpleDeadLock$B.run(SimpleDeadLock.java:56)

-waitingtolock(ajava.lang.Object)

-locked(ajava.lang.Object)

“线程-0”:

atcom.leo.interview.SimpleDeadLock$A.run(SimpleDeadLock.java:34)

-waitingtolock(ajava.lang.Object)

-locked(ajava.lang.Object)

发现1个死锁。

/*内存使用情况,详细请参考JVM书籍*/

PSYoungGentotal37888K,已使用4590K[0x00000000d6100000,0x00000000d8b00000,0x00000)

edenspace32768K,14%已使用[0x00000000d6100000,0x00000000d657b968,0x00000000d8100000)

fromspace5120K,0%已使用[0x00000000d8600000,0x00000000d8600000,0x00000000d8b00000)

tospace5120K,0%已使用[0x00000000d8100000,0x00000000d8100000,0x00000000d8600000)

ParOldGental86016K,已使用0K[0x00000,0x00000,0x00000000d6100000)

对象空间86016K,0%已使用[0x00000,0x00000,0x00000)

元空间已使用3474K,容量4500K,已提交4864K,保留1056768K

类空间已使用382K,容量388K,已提交512K,保留1048576K

19. 为什么调用start()方法时会执行run()方法?为什么我们不能直接调用run()方法呢?

当您调用 start() 方法时,您将创建一个新线程并执行 run() 方法中的代码。

但如果直接调用run()方法,它不会创建新线程或执行调用线程的代码。它只会像普通方法一样执行 run 方法。

20. Java中如何唤醒阻塞的线程?

在Java的开发历史中,曾使用过suspend()和resume()方法来阻塞和唤醒线程,但是也出现了很多问题,最典型的就是死锁。

解决方案可以是使用面向对象的阻塞,即使用Object类的wait()和notify()方法来实现线程阻塞。

首先,wait和notify方法是针对对象的。调用任何对象的wait()方法都会导致线程阻塞。当阻塞时,对象的锁也会被释放。相应地,调用任意对象的notify()方法,都会随机解除该对象阻塞的线程,但需要重新获取该对象的锁,直到获取成功才能继续;其次,wait和notify方法必须在synchronized块或方法中调用,并且synchronized块或方法的锁对象必须与调用wait和notify方法的对象相同。这样,当前线程在调用wait之前就已经成功获取到某个对象了。对象锁。执行等待阻塞后,当前线程将释放之前获取的对象锁。

21.Java中CycliBarriar和CountdownLatch有什么区别?

CyclicBarrier可以重复使用,但是CountdownLatch不能重复使用。

Java的concurrent包中的CountDownLatch其实可以看成是一个计数器,只不过这个计数器的操作是一个原子操作。只有一个线程可以同时操作这个计数器,即只有一个线程可以同时递减这个计数器。价值。

您可以设置一个初始数字作为 CountDownLatch 对象的计数值。任何对该对象的await()方法的调用都会阻塞,直到该计数器的计数值被其他线程减为0。

因此,await 方法将阻塞,直到当前计数达到零。之后,所有等待线程将被释放,并且所有后续对await的调用将立即返回。此行为仅发生一次 - 计数无法重置。如果需要重置计数,请考虑使用 CyclicBarrier。

CountDownLatch一个非常典型的应用场景是:有一个任务想要执行,但必须等到其他任务完成后才能继续执行。如果我们想要继续执行的任务调用了一个 CountDownLatch 对象的await()方法,而其他任务在完成自己的任务后又调用了同一个 CountDownLatch 对象上的 countDown() 方法,那么调用await()方法的任务就会阻塞并等待,直到此 CountDownLatch 对象的计数值减少到 0。

CyclicBarrier 是一个同步帮助器类,它允许一组线程相互等待,直到到达公共屏障点。 CyclicBarrier 在涉及一组必须不时相互等待的固定大小线程的程序中非常有用。由于屏障在等待线程被释放后可以重复使用,因此称为循环屏障。

22. 什么是不可变对象,它如何帮助编写并发应用程序?

不可变对象(Immutable Objects)是指对象一旦创建,其状态(对象数据,即对象属性值)就不能改变,否则称为可变对象(Mutable Objects)。

不可变对象的类是 Immutable Class。 Java平台类库包含许多不可变类,例如String、基本类型包装类、BigInteger和BigDecimal等。

不可变对象本质上是线程安全的。它们的常量(字段)是在构造函数中创建的。由于它们的状态无法修改,因此这些常量永远不会改变。

不可变对象始终是线程安全的。

一个对象只有满足以下条件才是不可变的;

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

在上下文切换过程中,CPU会停止处理当前正在运行的程序,并保存当前程序的具体位置以便稍后继续运行。从这个角度来看,上下文切换有点像我们同时阅读几本书。在来回切换书籍时,我们需要记住每本书的当前页码。程序中,上下文切换时的“页号”信息存储在进程控制块(PCB)中。 PCB也常被称为“开关框架”。 “页码”信息保存在CPU的内存中,直到再次使用。

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

24、Java中使用的线程调度算法是什么?

计算机通常只有一个CPU,任何时候只能执行一条机器指令。每个线程只有获得CPU的使用权后才能执行指令。所谓多线程的并发操作,实际上是指从宏观上看,每个线程轮流获得CPU使用权,分别执行各自的任务。在运行池中,会有多个处于就绪状态的线程等待CPU。 JAVA虚拟机的任务之一就是负责线程调度。线程调度是指按照特定的机制来调度多个线程。线程分配CPU使用权。

调度模型有两种:分时调度模型和抢占式调度模型。

分时调度模型是指所有线程轮流获得CPU的使用权,并且每个线程占用的CPU的时间片是均匀分布的。这也比较容易理解。

Java虚拟机采用抢占式调度模型,这意味着可运行池中优先级较高的线程会优先占用CPU。如果可运行池中的线程具有相同的优先级,则随机选择一个线程来占用CPU。处于运行状态的线程将继续运行,直到它必须放弃CPU。

25. 什么是线程组?为什么在 Java 中不推荐使用它?

线程组和线程池是两个不同的概念,其功能也完全不同。前者是为了方便线程管理,后者是为了管理线程的生命周期,复用线程,减少创建和销毁线程的成本。

26. 为什么使用Executor框架比使用应用程序创建和管理线程更好?

为什么要使用Executor线程池框架

每次执行任务时创建一个线程new Thread()会消耗性能。创建线程非常耗时且占用资源。

调用new Thread()创建的线程缺乏管理,称为野线程,可以无限制地创建。线程之间的竞争会导致系统资源的过度使用并导致系统瘫痪,以及线程之间的频繁交替。它还会消耗大量的系统资源。

直接使用new Thread()启动的线程不利于扩展,比如定时执行、周期执行、定时周期执行、线程中断等都不方便实现。

使用Executor线程池框架的优点

它可以复用现有的和空闲的线程,从而减少线程对象的创建,减少线程死亡的开销。

可以有效控制最大并发线程数,提高系统资源利用率,避免资源过度竞争。

该框架已经具备定时、周期、单线程、并发控制等功能。

综上所述,使用线程池框架Executor可以更好的管理线程,提高系统资源利用率。

27、Java中可以用多少种方法来实现线程?

28. 如何停止正在运行的线程?

29.notify()和notifyAll()有什么区别?

当一个线程进入wait时,它必须等待其他线程notify/notifyall。使用notifyall可以唤醒所有处于等待状态的线程并重新进入锁竞争队列,而notify只能唤醒一个。

如果不确定,建议使用notifyAll,防止notigy因信号丢失导致程序异常。

30.什么是守护线程?有什么意义?

所谓后台(守护)线程是指程序运行时在后台提供一般服务的线程,而这个线程并不是程序中不可缺少的部分。因此,当所有非后台线程结束时,程序终止,进程中的所有后台线程都被杀死。

相反,只要任何非后台线程正在运行,程序就不会终止。必须在线程启动之前调用 setDaemon() 方法将其设置为后台线程。注意:后台进程将终止其 run() 方法,而不执行finally 子句。

例如:JVM的垃圾收集线程就是守护线程,Finalizer也是守护线程。

31、Java如何实现多线程间的通信与协作?

中断和共享变量

32.什么是可重入锁(ReentrantLock)?

举例说明锁的可重入性

公共类不可重入{

锁锁=newLock();

公共无效外部(){

锁.lock();

内();

锁.解锁();

公共无效内部(){

锁.lock();

//做某事

锁.解锁();

在outer中调用inner,outer先把锁加锁,所以inner就无法再获取锁了。事实上更多公务员考试网题库就点击这里,调用outer的线程已经获取了锁,但是它无法复用inner中获取的锁资源。这种锁称为不可重入锁。可重入性的意思是:线程可以进入它已经拥有的任何一个线程。锁同步到的代码块。

Synchronized 和 ReentrantLock 都是可重入锁。可重入锁相对简化了并发编程的开发。

33、当一个线程进入一个对象的同步实例方法时,其他线程是否可以进入该对象的其他方法?

如果其他方法没有同步,其他线程就可以进入。

因此,在打开线程安全对象时,必须保证每个方法都是线程安全的。

34、乐观锁和悲观锁的理解和实现是什么?实施方法有哪些?

悲观锁:总是假设最坏的情况。每次你去获取数据的时候,你都认为别人会修改它,所以你每次获取数据的时候都会加锁。这样,如果其他人想要获取数据,就会阻塞,直到获得锁。 。传统关系数据库中使用了很多这样的锁机制,比如行锁、表锁、读锁、写锁等,都是在操作之前加锁。再比如Java中synchronized关键字的实现也是悲观锁。

乐观锁:顾名思义,非常乐观。每次你去获取数据的时候,你认为别人不会修改它,所以你不会锁它。不过更新的时候,你会判断这段时间其他人是否更新了数据。你可以使用它。版本号和其他机制。乐观锁适合多读应用类型,可以提高吞吐量。数据库提供的write_condition机制实际上是一种乐观锁。在Java中,java.util.concurrent.atomic包下的原子变量类是使用乐观锁的一种实现方法CAS来实现的。

如何实现乐观锁:

CAS缺点:

35.SynchronizedMap和ConcurrentHashMap有什么区别?

SynchronizedMap 一次锁定整个表以确保线程安全,因此一次只有一个线程可以访问该映射。

ConcurrentHashMap使用分段锁来保证多线程下的性能。在ConcurrentHashMap中,一次锁定一个桶。 ConcurrentHashMap默认将哈希表分为16个桶。 get、put、remove等常见操作仅锁定当前需要的桶。这样原本只能有1个线程进入,现在可以同时执行16个写入线程。并发性能的提升是显而易见的。

另外,ConcurrentHashMap使用不同的迭代方法。在此迭代方法中,当创建迭代器且集合发生更改时,不再抛出 ConcurrentModificationException。相反,在更改期间新数??据是新的,因此原始数据不受影响。迭代器完成后,头指针被替换。作为新数据,这样迭代器线程就可以使用原来的旧数据,写入线程也可以并发完成更改。

36、CopyOnWriteArrayList可以用于哪些应用场景?

CopyOnWriteArrayList(无锁容器)的好处之一是,多个迭代器同时遍历并修改列表时,不会抛出ConcurrentModificationException。在 CopyOnWriteArrayList 中,写入将导致创建整个底层数组的副本,而源数组将保留在原处,从而允许在修改复制的数组时安全地执行读取操作。

由于写操作时需要复制数组,因此会消耗内存。如果原数组包含大量内容,可能会导致young gc或full gc;

无法用于实时阅读场景。复制数组并添加新元素需要时间。因此,调用set操作后,读取的数据可能仍然是旧的。虽然CopyOnWriteArrayList可以达到最终一致性,但仍然无法满足实时性要求。性要求;

CopyOnWriteArrayList 揭示的想法

37.什么是线程安全? Servlet 是线程安全的吗?

线程安全是编程中的一个术语,指的是在多线程环境下调用某个函数或函数库时,能够正确处理多个线程之间的共享变量,从而使程序功能能够正确完成。

Servlet 不是线程安全的。 Servlet是单实例多线程。当多个线程同时访问同一个方法时,共享变量的线程安全无法保证。

Struts2的动作是多实例、多线程的,并且是线程安全的。每次有请求进来,就会给该请求分配一个新的action,请求完成后就会销毁。

SpringMVC的Controller是线程安全的吗?不是,处理流程和Servlet类似

Struts2的优点是不需要考虑线程安全问题; Servlet和SpringMVC需要考虑线程安全问题,但无需处理过多的gc即可提高性能,并且可以使用ThreadLocal来处理多线程问题。

38. 挥发性有什么用?能用一句话解释一下 volatile 的应用场景吗?

易失性保证内存可见性并禁止指令重新排序。

Volatile用于多线程环境中的单次操作(单次读或单次写)。

39. 为什么代码会重新排序?

在执行程序时,为了提高性能,处理器和编译器经常会对指令进行重新排序,但不能随意重新排序。您无法根据需要对它们重新排序。它需要满足以下两个条件:

需要注意的是,重排序不会影响单线程环境的执行结果,但会破坏多线程的执行语义。

40. Java中wait和sleep方法有什么区别?

最大的区别是wait在等待时释放锁,而sleep始终持有锁。 wait通常用于线程之间的交互,sleep通常用于暂停执行。

让我们更直接地了解一下:

在Java中,线程的状态分为6种:

初始状态:新

当Thread对象被创建但尚未调用start()来启动线程时,线程处于初始状态。

运行状态:RUNNABLE

在Java中,运行状态包括就绪状态和运行状态。

就绪状态 该状态的线程已获得执行所需的全部资源,只要CPU分配执行权就可以运行。所有就绪线程都存储在就绪队列中。

运行状态获得CPU执行权,是正在执行的线程。由于CPU一次只能执行一个线程,因此每个CPU一次只能运行一个线程。

阻塞状态

当正在执行的线程请求资源失败时,它将进入阻塞状态。在Java中,阻塞状态特指锁请求失败时进入的状态。阻塞队列存储所有被阻塞的线程。处于阻塞状态的线程将继续请求资源。一旦请求成功,就会进入就绪队列等待执行。 PS:Lock、IO、Socket等都是资源。

等待状态

当当前线程中调用wait、join、park函数时,当前线程将进入等待状态。还有一个等待队列,用来存放所有等待的线程。处于等待状态的线程意味着它需要等待其他线程的指令才能继续运行。进入等待状态的线程会释放CPU执行权并释放资源(如锁)

超时等待状态

当正在运行的线程调用sleep(time)、wait、join、parkNanos、parkUntil时,就会进入该状态;和等待状态一样,不是因为资源无法被请求,而是因为它主动进入,需要其他Thread唤醒;进入该状态后,CPU执行权和占用的资源被释放。与等待状态的区别:达到超时时间后,自动进入阻塞队列,开始竞争锁。

终端状态

线程执行结束后的状态。

注意:

41、线程运行时出现异常怎么办?

如果没有捕获异常,线程将停止执行。 Thread.UncaughtExceptionHandler是一个嵌入式接口,用于处理未捕获的异常导致的线程突然中断。当未捕获的异常将导致线程中断时,JVM将使用Thread.getUncaughtExceptionHandler()来查询线程的UncaughtExceptionHandler,并将线程和异常作为参数传递给处理程序的uncaughtException()方法进行处理。

42. 两个线程之间如何共享数据?

共享是通过在两个线程之间共享变量来实现的。

一般来说,共享变量要求变量本身是线程安全的。在线程内使用时,如果对共享变量有复合操作,也必须保证复合操作的线程安全。

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

notify()方法不能唤醒特定的线程,所以它只有在线程等待时才有用。而notifyAll()会唤醒所有线程,让它们竞争锁,以保证至少有一个线程可以继续运行。

44.为什么wait、notify和notifyAll方法不在线程类中?

一个明显的原因是JAVA提供的锁是在对象级别而不是线程级别。每个对象都有一个锁,它是通过线程获得的。由于wait、notify和notifyAll是锁级操作,因此它们被定义在Object类中,因为锁属于对象。

45.什么是ThreadLocal变量?

ThreadLocal是Java中的一个特殊变量。每个线程都有一个ThreadLocal,这意味着每个线程都有自己的独立变量,完全消除了竞争条件。对于创建成本高昂的对象来说,这是获得线程安全的好方法,例如,您可以使用 ThreadLocal 使 SimpleDateFormat 线程安全,因为该类的创建成本很高,并且需要为每个调用创建不同的实例,因此不值得在局部作用域 使用它,如果每个线程都提供自己唯一的变量副本,效率将大大提高。首先,通过重用减少了创建的昂贵对象的数量。其次,您无需使用昂贵的同步或不变性即可获得线程安全性。

46.Java中的interrupted和isInterrupted方法有什么区别?

打断

中断方法用于中断线程。调用该方法的线程的状态将被设置为“中断”状态。

注意:线程中断只是设置线程的中断状态位,并不停止线程。用户需要监控线程的状态并自行处理。支持线程中断的方法(即线程被中断后抛出interruptedException的方法)就是监视线程的中断状态。一旦线程的中断状态被设置为“已中断状态”,就会抛出中断异常。

被打断

查询当前线程的中断状态并清除原有状态。如果线程被中断,则第一次调用 Interrupted 返回 true,第二次及后续调用返回 false。

被中断

只需查询当前线程的中断状态

47. 为什么在synchronized块中调用wait和notify方法?

Java API 强制执行此操作,如果您不执行此操作,您的代码将抛出 IllegalMonitorStateException。另一个原因是避免等待和通知之间的竞争条件。

48. 为什么要在循环中检查等待条件?

处于等待状态的线程可能会收到误报和虚假唤醒,如果在循环中没有检查等待条件,则程序将在不满足结束条件的情况下退出。

49. Java中同步集合和并发集合有什么区别?

同步集合和并发集合都为多线程和并发提供了合适的线程安全集合,但并发集合更具可扩展性。在Java 1.5之前,程序员只能使用同步集合,这会导致多个线程并发运行时出现争用,阻碍系统的可扩展性。 Java 5 引入了像 ConcurrentHashMap 这样的并发集合,它不仅提供了线程安全性,而且还通过锁分离和内部分区等现代技术提高了可扩展性。

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

创建线程会耗费昂贵的资源和时间。如果只有任务来了才创建线程,那么响应时间会变长,而且一个进程可以创建的线程数量是有限的。为了避免这些问题,程序启动时会创建几个线程来响应处理。它们被称为线程池,里面的线程被称为工作线程。从JDK1.5开始,Java API提供了Executor框架,以便你可以创建不同的线程池。

51、如何检测一个线程是否拥有锁?

java.lang.Thread中有一个方法叫holdsLock(),当且仅当当前线程持有特定对象的锁时,该方法返回true。

52.Java中如何获取线程堆栈?

53、JVM中哪个参数用来控制栈最小的线程栈?

-Xss 每个线程的堆栈大小

54.Thread类中yield方法的作用是什么?

将当前线程从执行状态(运行状态)更改为可执行状态(就绪状态)。

当前线程已经达到了就绪状态,那么接下来哪个线程会从就绪状态转入执行状态呢?它可能是当前线程,也可能是另一个线程,具体取决于系统的分配。

55、Java中ConcurrentHashMap的并发度是多少?

ConcurrentHashMap 将实际的映射分为几个部分,以实现其可扩展性和线程安全性。这种划分是使用并发性获得的,并发性是ConcurrentHashMap类构造函数的可选参数,默认值为16,这可以避免多线程情况下的争用。

JDK8之后,放弃了Segment(锁段)的概念,转而启用了一种新的实现方式,即使用CAS算法。同时还增加了更多的辅助变量来提高并发性。详情请查看源代码。

56.Java中的信号量是什么?

Java中的信号量是一个新的同步类,它是一种计数信号。从概念上讲,信号量维护一个许可的集合。如果有必要,每个acquire()都会被阻塞,直到有权限为止,然后再获取权限。每个release()都会添加一个权限,可能会释放一个阻塞的获取者。然而,Semaphore 并不使用实际的权限对象,而是简单地计算可用权限的数量并采取相应的操作。信号量经常用在多线程代码中,例如数据库连接池。

57。在Java线程池中cumber()和execute()方法之间有什么区别?

两种方法都可以将任务提交到线程池。 execute()方法的返回类型是无效的,在执行程序接口中定义。

提交方法可以返回保留计算结果的未来对象。它是在执行人员服务接口中定义的,该接口扩展了执行程序接口。其他线程池类,例如ThreadPoolExecutor和ScheduleDthRe??adPoolExecutor,具有这些方法。

58。什么是阻止方法?

阻止方法意味着程序将等待该方法完成而无需做任何其他操作。 serverversocket的Accept()方法是等待客户端连接。这里的阻塞意味着在返回呼叫结果之前,将暂停当前线程,并且在获得结果之前不会返回。此外,在任务完成之前,还有异步和非阻滞方法。

59。什么是Java的ReadWritelock?

读写锁是用于提高并发程序性能的锁分离技术的结果。

60。挥发性变量和原子变量之间有什么区别?

挥发性变量可以确保看起来很现实的关系,也就是说,在随后的读取操作之前将进行写操作,但不能保证原子能。例如,如果计数变量通过挥发性修改,则计数++操作不是原子。

原子类别提供的原子方法可以使此操作原子能。例如,GetAndIncrement()方法将在原子上执行一个增量操作,以将一个添加到当前值中。也可以在其他数据类型和参考变量上执行类似的操作。

61。线程类的运行()方法可以直接调用吗?

当然。但是,如果我们调用thread's run()方法,它将像普通方法一样行为,并将在当前线程中执行。为了在新线程中执行我们的代码,必须使用thread.start()方法。

62。如何在一段时间内暂停运行线程?

我们可以使用线程类的Sleep()方法来暂停线程一段时间。应该注意的是,这不会终止线程。一旦线程从睡眠中唤醒,线程的状态将更改为可运行的,并且将根据线程时间表执行。

63。您对线程优先级有何了解?

每个线程都有一个优先级。一般而言,运行时高优先级线程将优先,但这取决于线程调度的实现,这是OS依赖的。我们可以定义线程的优先级,但这不能保证高优先级线程将在低优先级线程之前执行。线程优先级是一个int变量(从1-10起),1表示最低的优先级,10表示优先级。

Java的线程优先计划将委托给操作系统进行处理,因此它与特定的操作系统优先级有关。除非另有必要,否则通常无需设置线程优先级。

64。什么是线程调度程序和时间切片?

线程调度程序是一种操作系统服务,负责将CPU时间分配给可运行状态的线程。创建线程并启动该线程后,其执行取决于线程调度程序的实现。

与上一个问题相同,线程调度不是由Java虚拟机控制的,因此应用程序更好地控制它(也就是说,不要让您的程序取决于线程的优先级)。

时间切片是指将可用的CPU时间分配给可运行的线程的过程。分配CPU时间可以基于线程优先级,也可以基于线程等待的时间。

65。如何确保主()方法所在的线程是Java程序结束的最后一个线程?

我们可以使用线程类的JOIN()方法来确保在Main()方法退出之前由程序结束创建的所有线程。

66。线程如何相互通信?

当线程之间可以共享资源时,线程间通信是协调它们的重要手段。对象类中的wait()otify()otifyall()方法可用于与资源锁状态的线程之间进行通信。

67。为什么线程通信方法wait(),notify()和对象类中定义的notifyall()?

Java中的每个对象都有一个锁定(监视器,也可以是监视器),并且使用wait()和notify()之类的方法等待对象的锁定或通知其他线程。 Java线程中的任何对象都没有可用的锁或同步器。这就是为什么这些方法是对象类的一部分,以便Java中的每个类都有用于线际间交流的基本方法。

68。为什么必须以同步方法或同步块来调用wait(),notify()和notifyall()?

当线程需要调用对象的wait()方法时,该线程必须具有对象的锁定,然后它将释放此对象锁定并输入等待状态,直到其他线程在此对象上调用notify()方法。同样,当线程需要调用对象的notify()方法时,它会释放此对象的锁定,以便其他等待线程可以获取此对象锁定。因为所有这些方法都需要线程固定对象的锁定,因此只能通过同步实现它们,因此只能在同步方法或同步块中调用它们。

69。为什么线程类睡眠()和fart()方法静态?

线程类Sleep()和farte()方法将在当前执行的线程上运行。因此,在其他等待状态上调用这些方法是毫无意义的。这就是为什么这些方法是静态的。他们可以在当前执行的线程中工作,并避免程序员的错误,这些错误可以在其他非交易线程上调用这些方法。

70。如何确保线程安全?

有很多方法可以确保Java -synchronization中的线程安全性,使用原子Conmict类,实现并发锁,使用挥发性关键字,并使用不请自来的类和线程安全类。

71。同步方法和同步块,这是一个更好的选择?

同步块是一个更好的选择,因为它不会锁定整个对象(当然,您也可以让它锁定整个对象)。同步方法将锁定整个对象,即使此类中有许多无关的同步块,这通常会导致它们停止执行,并且需要等待该对象上的锁定。

同步块必须符合公开通话的原则。它仅锁定需要锁定的代码块中的相应对象,以便可以从侧面避免僵局。

72。如何创建守护线?

线程类的SetDaemon(true)方法可以设置为Guardian线程。应当指出,在调用start()方法之前需要调用此方法,否则将抛出非法读书。

73。什么是Java计时器类?如何使用特定时间间隔创建任务?

java.util.timer是一种工具类,可以在将来在某个时间安排线程。可以安排计时器类的一次性或周期性任务。

Java.util.timtask是一个抽象类,可实现可运行的接口。我们需要继承此类以创建自己的计时任务并使用计时器来安排其执行。

目前,开源Qurtz可用于创建正时任务。

推荐的程序员必需微观信号

程序员的内部参考

公务员考试网推荐专题
你可能还会关注的文章
公务员考试网最新文章
公务员考试网热门文章
公务员考试网推荐
 
网站留言 | 关于我们 | 广告业务 | 信息反馈 | 合作伙伴 | 网站地图
版权所有 2007-2023 甘肃公务员考试网(www.gsgwyw.com)
Copyright © 2007-2023 www.gsgwyw.com Incorporated. All rights reserved.