b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

java多线程面试问答(2019)

电脑杂谈  发布时间:2020-03-31 19:13:22  来源:网络整理

线程 死锁_linux 线程死锁_java多线程死锁

线程是操作系统可以执行算术调度的最小单元. 它包含在过程中,并且是过程中的实际操作单元. 程序员可以将其用于多处理器编程,并且您可以使用多线程来加速计算密集型任务. 例如,如果一个线程花费100毫秒来完成一项任务,那么只需十毫秒就可以完成十个线程来完成任务. Java在语言级别为多线程提供了出色的支持,这也是一个很好的卖点.

线程是进程的子集. 一个进程可以有很多线程,并且每个线程并行执行不同的任务. 不同的进程使用不同的内存空间,并且所有线程共享相同的内存空间. 不要将其与堆栈内存混淆,每个线程都有一个单独的堆栈内存来存储本地数据.

在语言级别有三种方法. java.lang.Thread类的实例是一个线程,但需要调用java.lang.Runnable接口才能执行. 由于线程类本身是调用的Runnable接口java多线程死锁,因此可以继承java.lang.Thread类或直接调用Runnable接口. 编写run()方法以实现线程. 第三个实现Callable <>接口并覆盖call方法.

此问题是上一个问题的后续. 每个人都知道我们可以通过扩展Thread类或调用Runnable接口来实现线程. 问题是,哪种方法更好?什么时候使用?如果您知道Java不支持类的多重继承,但允许您调用多个接口,则很容易回答此问题. 因此,如果您想继承其他类,请调用Runnable接口.

这个问题经常被问到,但是仍然有可能区分受访者对Java线程模型的理解. start()方法用于启动新创建的线程,start()在内部调用run()方法,其效果与直接调用run()方法不同. 当您调用run()方法时,它将仅在原始线程中被调用. 没有要启动的新线程,而start()方法将启动新线程.

Runnable和Callable都表示要在不同线程中执行的任务. 从JDK 1.0开始就可以使用Runnable,并且在JDK 1.5中添加了Callable. 主要区别在于Callable的call()方法可以返回值并引发异常,而Runnable的run()方法不具有这些功能. Callable可以返回装载了计算结果的Future对象.

volatile是一个特殊的修饰符,只有成员变量可以使用它. 它保证了在对该变量进行操作时不同线程的可见性,即一个线程更改了变量的值,新值立即对其他线程可见.

如果您有多个线程在与代码相同的进程中运行,则这些线程可以同时运行此代码. 如果每次运行的结果与单线程运行的结果相同,并且其他变量的值与预期的相同,则是线程安全的. 线程安全计数器类的同一实例对象即使被多个线程使用也不会引起计算错误. 显然,您可以将集合类分为两组,线程安全的和非线程安全的. 使用同步方法,vector是线程安全的,而类似的ArrayList也不是线程安全的.

这是另一个棘手的问题,因为多线程可以等待单个监视器锁定. Java API的设计器提供了一些方法,可以在等待条件改变时通知它们,但是这些方法尚未完全实现. notify()方法无法唤醒特定线程,因此仅在一个线程正在等待时才有用. NotifyAll()唤醒所有线程并允许它们竞争锁,以确保至少一个线程可以继续运行.

这是与设计有关的问题. 它检查了访调员对现有系统的观点以及一些常见但看起来不合理的事物. 在回答这些问题时,您必须解释为什么将这些方法放在Object类中是有意义的,以及为什么不将它们放在Thread类中是为什么. 一个明显的原因是JAVA提供的锁是对象级而不是线程级的. 每个对象都有一个锁,该锁是通过线程获得的. 如果线程需要等待一些锁定,则可以在对象上调用wait()方法. 如果在Thread类中定义了wait()方法,则线程正在等待哪个锁并不明显. 简而言之,因为wait,notify和notifyAll是锁级操作,所以它们在Object类中定义,因为锁属于对象.

linux 线程死锁_线程 死锁_java多线程死锁

ThreadLocal主要用于解决由于多个线程中的数据并发导致的不一致问题. ThreadLocal提供每个线程中同时访问的数据的副本,并通过访问该副本来经营业务. 这会导致内存消耗,从而大大减少线程同步带来的性能消耗,并降低线程并发控制程度的复杂性.

ThreadLocal不能使用原子类型,只能使用对象类型. ThreadLocal的使用比同步要简单得多.

ThreadLocal和Synchonized用于解决多线程并发访问. 但是ThreadLocal从根本上不同于同步. 同步是一种使用锁的机制,因此变量或代码块一次只能由一个线程访问. ThreadLocal为每个线程提供变量的副本,以便每个线程在特定时间不访问同一对象,从而将多个线程之间的数据共享隔离开来. 同步恰好相反. 在多个线程之间进行通信时,它用于获取数据共享.

FutureTask表示可以在Java并发程序中取消的异步操作. 它具有用于启动和取消操作,查询操作是否完成以及检索操作结果的方法. 仅当操作完成时才能检索结果,如果操作尚未完成,则get方法将阻塞. FutureTask对象可以打包调用Callable和Runnable的对象. 由于FutureTask也调用Runnable接口,因此可以将其提交给执行程序以执行.

两者之间的主要区别

interrupted()和isInterrupted()是前者将清除中断状态,而后者将不清除. Java多线程中断机制是通过内部标识符实现的. 调用Thread.interrupt()中断线程会将中断标志设置为true. 当中断线程调用静态方法Thread.interrupted()检查中断状态时,将清除中断状态. 非静态方法isInterrupted()用于查询其他线程的中断状态,而不更改中断状态标志. 简而言之,任何引发InterruptedException的方法都会将中断状态清除为零. 在任何情况下,一个线程的中断状态都可以由其他线程调用中断来更改.

这主要是因为Java API强制执行此操作. 如果不这样做,您的代码将抛出IllegalMonitorStateException. 另一个原因是要避免在等待和通知之间出现竞争状况.

处于等待状态的线程可能会收到错误的警报和错误的唤醒. 如果循环中未检查等待条件,则程序将不满足结束条件而退出. 因此,当等待线程唤醒时,不能认为其原始等待状态仍然有效. 在调用notify()方法之后以及在等待线程唤醒之前,它可能会更改. 这就是为什么在循环中使用wait()方法更有效的原因. 您可以在Eclipse中创建一个模板来调用wait并通知您尝试一下. 如果您想了解更多有关此问题的信息,建议阅读有效Java一书中的“线程和同步”一章.

同步集合和并发集合都为多线程和并发提供了合适的线程安全集合,但是并发集合具有更高的可伸缩性. 在Java 1.5之前,程序员仅使用同步集合,并且在多线程并发时会引起争用,从而阻碍了系统的可伸缩性. Java 5引入了诸如ConcurrentHashMap之类的并发集合,该集合不仅提供线程安全性,还使用锁分离和内部分区等现代技术来提高可伸缩性.

为什么要将此问题归类为多线程和并发面试问题?因为堆栈是与线程紧密相关的内存块. 每个线程都有其自己的堆栈内存,该内存用于存储局部变量,方法参数和堆栈调用. 一个线程中存储的变量对其他线程不可见. 堆是所有线程共享的公共内存区域. 在堆中创建对象. 为了提高效率,线程将从堆中获取一个缓存到其自己的堆栈. 如果多个线程使用此变量,则可能会导致问题. 这时,volatile变量可以发挥作用,它要求线程从主线程开始读取内存中变量的值.

java多线程死锁_linux 线程死锁_线程 死锁

创建线程需要花费大量资源和时间. 如果在创建线程之前创建任务,则响应时间将更长,并且进程可以创建数量有限的线程. 为避免这些问题,在启动程序时,将创建多个线程来响应处理. 它们称为线程池,内部的线程称为工作线程. 从JDK 1.5开始,Java API提供了Executor框架,因此您可以创建不同的线程池. 例如,单线程池一次处理一个任务. 固定数量的线程池或高速缓存的线程池(适用于许多短期任务的可伸缩线程池).

实际上,您解决的许多线程问题都属于生产者-消费者模型,也就是说,一个线程会生成任务供其他线程使用. 您必须知道如何执行线程间通信来解决此问题. 下层方法是使用等待和通知来解决此问题. 更好的方法是使用Semaphore或BlockingQueue来实现生产者-消费者模型. 本教程已实现.

Java多线程中的死锁

死锁是指由于执行过程中对资源的竞争而导致两个或多个进程互相等待的现象. 没有外力,他们将无法前进. 这是一个严重的问题,因为死锁将使您的程序挂起并且无法完成任务. 死锁的发生必须满足以下四个条件:

避免死锁的最简单方法是防止循环等待条件,设置标志并对系统中的所有资源进行排序,并规定所有申请资源的进程必须以一定的顺序(升序或降序)操作以避免死锁.

这是上一个问题的扩展. 活锁类似于死锁. 区别在于,活动锁中的线程或进程的状态不断变化. 活锁可以被认为是一种特别的饥饿. 一个活锁的现实例子是两个人在狭窄的走廊里相遇. 双方都试图避开对方让彼此通过,但是由于避让的方向相同,所以最终没人可以通过走廊. 简而言之,活动锁和死锁之间的主要区别在于前一个进程的状态可以更改,但不能继续执行.

在参加电话采访之前,我一直不知道我们能否检测到线程是否拥有锁. 在java.lang.Thread中有一个名为holdLock()的方法,当且仅当当前线程拥有对特定对象的锁时,该方法才返回true.

对于不同的操作系统,有多种方法来获取Java进程的线程堆栈. 当您获得线程堆栈时,JVM会将所有线程的状态保存到日志文件或输出到控制台. 在Windows上,可以使用Ctrl + Break键组合获取线程堆栈,在Linux上,可以使用kill -3命令. 您还可以使用jstack工具获取线程ID. 您可以使用jps工具查找ID.

问题很简单,-Xss参数用于控制线程的堆栈大小.

linux 线程死锁_线程 死锁_java多线程死锁

过去,Java在很长一段时间内只能通过synced关键字实现互斥. 它有一些缺点. 例如,您不能扩展除锁以外的方法或块边界,也不能在尝试获取锁时中途取消. Java 5通过Lock接口提供更复杂的控件来解决这些问题. ReentrantLock类实现了Lock,它具有与同步相同的并发性和内存语义,并且还可以扩展.

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

Yield方法可以暂停当前正在执行的线程对象,并让其他具有相同优先级的线程执行. 它是一种静态方法,仅保证当前线程放弃CPU使用率,而不能保证其他线程必须占用CPU. 进入挂起状态后,可以立即执行执行yield()的线程.

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

Java中的信号量是一个新的同步类,它是一个计数信号. 从概念上讲,信号量维护一个权限集. 如有必要,在获取许可证之前会先阻止每个获得(). 每个release()都会添加一个权限,该权限可能会释放阻止获取者. 但是,在不使用实际许可证对象的情况下,信号量仅计算可用许可证的数量并采取相应的措施. 信号量通常用于多线程代码中,例如连接池.

这个问题很棘手. 许多程序员认为任务将阻塞,直到线程池队列为空. 实际上,如果无法安排任务的执行时间,则ThreadPoolExecutor的commit()方法将引发RejectedExecutionException.


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-159185-1.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    热点图片
    拼命载入中...