今天是:
带着程序的旅程,每一行代码都是你前进的一步,每个错误都是你成长的机会,最终,你将抵达你的目的地。
title

关于多线程问题

1.什么是线程

    线程是操作系统能够进行运算调度的最小单位, 在一个进程中,您可以使一个线程或多个线程共享同一进程资源。一个进程可以包含多个线程。

2.什么是多线程

  多线程是使多个线程同时执行的能力。尽管每个线程共享相同的进程资源,但它们彼此独立地运行。

3.线程和进程的区别是什么

  进程是单个应用程序或程序,而线程是该应用程序或程序内的子进程。 每个进程在内存中都有自己的地址空间。 线程共享它们的地址空间。

4.为什么使用多线程在应用程序中

  由于每个线程同时运行,因此多线程可以有效利用CPU。在应用程序接收用户输入的同时,您可以运行后台进程。而且,由于每个线程独立运行,因此任务可以更快地执行。

5.什么是线程池

   线程池是在启动时创建的工作线程的集合,可以根据需要分配任务,然后在完成时放回线程池。使用线程池的主要优点是,在需要它们的时候运行已创建的线程 ,从而提高应用程序性能。

6.线程有哪些状态

   线程可以具有五个状态:新建,可运行,正在运行,等待/阻止和已终止。

7.什么是竞态条件

   当多个并发线程争先运行时,就会发生竞争状态。如果赢得竞争的线程不是应该首先运行的线程,则代码可能表现出意外的行为。可以通过同步解决问题。

8.什么是同步

  同步会强制线程在同一时间只运行一个,以防止出现竞争状况或多个线程尝试执行同一任务。

9.为什么要使用同步块

  同步块使您可以将方法的特定部分指定为已同步。 也就是说,只有一个线程将被允许运行直到完成为止,该线程的优先级高于其他线程。通过同步代码块而不是整个方法,可提高代码运行效率。

10.什么是上下文切换

  上下文切换是存储线程或进程的当前状态的位置,因此可以在以后的时间恢复该线程的执行。 这使单个CPU可以管理多个线程或进程。

  如果主线程是唯一的可调度线程,则几乎永远不会将其调度出去。可运行线程而不是CPU,最终操作系统将抢占一个线程,以便另一个线程可以使用CPU。这将导致上下文切换,这需要保存当前正在运行的线程的执行上下文,并还原新调度的线程的执行上下文。
上下文切换需要一定的开销;线程调度需要在OS和JVM中操纵共享的数据结构,OS和JVM使用相同的CPU。您的程序可以做到;花费在JVM和OS代码上的CPU时间更多意味着您的程序可以使用的时间更少,但是OS和JVM活动不是上下文切换的唯一开销。当一个新线程被切换时,它所需的数据不太可能被放入本地处理器高速缓存,因此上下文切换会导致大量高速缓存未命中,因此线程在运行时会慢一些首先进行调度,这是调度程序为每个可运行线程分配一定的最小时间量的原因之一,即使有许多其他线程都在等待:它在不间断的执行时间内分摊了上下文切换的成本及其后果,从而提高了总体吞吐量(一些响应成本)。

11.解释一下线程调度程序是什么及其与线程优先级的关系

   线程调度程序负责为线程分配CPU执行时间片并确定线程执行的顺序。处于就绪状态的线程,谁的优先级高,优先被调度的概率会高于其他线程。

12.什么是时间片

  时间分片是线程调度程序用来在就绪状态的线程之间划分CPU时间的过程。

13.为什么将线程行为描述为不可预测的?

  由于线程调度是由CPU确定的,因此不同的CPU可以为不同的线程赋予优先级。 这意味着两个CPU可能不会以相同的顺序运行线程,从而在代码执行中产生了不可预测性。

14.解释忙碌等待(Busy spinning)技术以及为什么要使用它

   忙碌等待是一种等待策略,其中一个线程循环不断地检查某些条件,并等待其他线程更改此条件以中断循环而无需释放CPU,以便等待线程可以继续进行其工作。传统的线程方法(例如sleep,Wait()和notify())会释放CPU,但是忙碌的旋转不会放弃CPU,因此会保留CPU缓存。

15. 什么是线程饥饿?

   饥饿描述了一种情况,即线程无法获得对共享资源的常规访问并且无法取得进展。当“贪婪”线程使共享资源长时间不可用时,就会发生这种情况。例如,假设一个对象提供了一个同步方法,该方法通常需要很长时间才能返回。如果一个线程频繁调用此方法,则也需要频繁同步访问同一对象的其他线程将经常被阻塞。

是否存在提供同步方法的对象,该方法需要大量处理时间。 如果有一个线程非常频繁地调用此方法,则其他也需要访问同步方法的线程将被阻塞。
如果有一些较高优先级的线程,则将优先执行那些线程,而不是优先级较低的线程。
如果使用的是wait-notify信号,那么从理论上讲,如果总是有其他线程被通知并可以访问共享资源,则等待访问共享资源的线程可能会无限期等待。

16.你能启动一个线程两次吗

   一旦线程被执行,它就被认为是死亡的。 您无法重新启动死线程。Java的线程是不允许启动两次的,第二次调用必然会抛出IllegalThreadStateException,这是一种运行时异常,多次调用start被认为是编程错误。

17.描述一个死锁的情况

   死锁情况是多个线程互相等待释放CPU资源以便它们可以运行。 例如,当单个线程具有独占优先级但需要来自等待线程的资源,或者所有线程都相互依赖以释放所需资源时,可能会发生这种情况。

18.什么是活锁,发生活锁时会发生什么

   是指线程1可以使用资源,但它很礼貌,让其他线程先使用资源,线程2也可以使用资源,但它很绅士,也让其他线程先使用资源。这样你让我,我让你,最后两个线程都无法使用资源. 

当两个或多个进程连续重复相同的交互以响应其他进程的更改而没有做任何有用的工作时,就会发生Livelock。 这些进程不处于等待状态,它们正在同时运行。 这与死锁不同,因为在死锁中,所有进程都处于等待状态。

19.wait() and sleep() 方法有什么不同

    Wait()-线程释放此监视器的所有权,并等待直到另一个线程通过调用notify()方法或notifyAll()方法通知等待在该对象的监视器上的线程唤醒。 然后,线程等待,直到它可以重新获得监视器的所有权并恢复执行。可以在任何对象上调用它,但是只能从同步块中调用它。 它释放对象上的锁,以便另一个线程可以跳入并获取锁。

    Sleep()-此方法使当前正在执行的线程进入休眠状态(暂时停止执行)达指定的毫秒数。 该线程不会失去任何监视器的所有权。 它将在指定的时间内将当前线程发送到“不可运行”状态。

20.什么是守护线程?

  守护程序线程是低优先级线程。 它可以为其他线程提供后台服务或支持。 当这些线程死亡时,守护程序线程将自动终止。守护程序线程是在程序完成但线程仍在运行时不会阻止JVM退出的线程。 守护程序线程的一个示例是垃圾回收。创建新线程时,它将继承其父级的守护程序状态。

21.为什么必须在线程类中重写run()方法

   调用线程的start()方法时,它将自动调用与该新线程关联的run()方法。 如果尚未覆盖run()方法,则该线程将不执行任何操作。

22.如何实现线程安全

  您可以通过多种技术来实现线程安全,包括使用Volatile关键字或原子包装器类进行同步。

  1. Using Synchronization.
  2. Using Volatile Keyword.
  3. Using Atomic Variable.
  4. Using Final Keyword.

23.同步编程和异步编程有什么区别?

    同步编程是指为单个线程分配单个任务。 异步编程是在多个线程之间共享单个任务时。

24.解释volatile关键字

  一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

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

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

24.如何在Java中停止线程

    在Java中,没有直接的方法来停止线程。 通常,您必须依靠这样的事实,即线程在执行完停止时将死亡。 如果需要手动终止线程,则可以在线程内使用Volatile布尔变量,该变量在从另一个线程触发时将引发异常。

  1.    使用一个布尔变量或volatile 类型的布尔变量停止线程,当条件为真时,run方法结束运行,线程停止。
  2. 使用线程Thread.interrupt()方法
  3. 使用线程池的shutdown方法停止线程

25.如何在Java中创建线程

您可以通过在类上实现Runnable接口并创建线程对象来用Java创建线程,也可以创建扩展线程类的类。

创建FutureTask对象,创建Callable子类对象,复写call(相当于run)方法,将其传递给FutureTask对象(相当于一个Runnable)。 创建Thread类对象,将FutureTask对象传递给Thread对象。调用start方法开启线程。这种方式可以获得线程执行完之后的返回值。该方法使用Runnable功能更加强大的一个子类.这个子类是具有返回值类型的任务方法。线程池创建

  

分享到:

专栏

类型标签

网站访问总量