您的位置  > 互联网

进程,线程是什么?如何检测一个线程的方式

说说进程、线程和协程的区别

简而言之,进程是程序运行和资源分配的基本单位。 一个程序至少有一个进程,一个进程至少有一个线程。 进程在执行时拥有独立的内存单元,多个线程共享内存资源,减少了切换次数,效率更高。 线程是进程的实体,是CPU调度和分派的基本单位,是比程序更小的、可以独立运行的基本单位。 同一进程中的多个线程可以并发执行。

你了解守护线程吗?它和非守护线程有什么区别?

程序运行完毕后,jvm会等待非守护线程完成然后关闭,但jvm不会等待守护线程。 守护线程最典型的例子是GC线程。

什么是多线程上下文切换

多线程上下文切换是指将CPU控制权从一个已经运行的线程切换到另一个准备好等待获取CPU执行权的线程的过程。

如何创建两个线程? 它们之间有什么区别?

通过实现java.lang。 或者通过扩展 java.lang。 班级。 与扩展相比,实现接口可能会更好。 原因有二:

Java不支持多重继承。 因此,扩展一个类意味着这个子类不能扩展其他类。 实现接口的类也可以扩展另一个类。

该类可能只需要可执行,因此继承整个类的成本太高。

类中的 start() 和 run() 方法有什么区别?

start()方法用于启动一个新创建的线程,start()内部调用了run()方法,与直接调用run()方法有不同的效果。 当你调用run()方法时,它只会在原来的线程中被调用。 如果没有启动新线程,start()方法将启动一个新线程。

如何检查线程是否可以持有对象监视器

该类提供了 (obj) 方法,当且仅当对象 obj 的监视器由线程持有时,该方法才会返回 true。 注意,这是一个方法,也就是说“线程”指的是当前线程。 。

和...之间的不同

接口中run()方法的返回值为void,其作用纯粹是执行run()方法中的代码; 接口中的call()方法有返回值,并且是泛型类型,配合可以获取异步执行的结果。

这其实是一个非常有用的特性,因为多线程比单线程更困难、更复杂的一个重要原因就是因为多线程充满了未知数。 某个线程可以执行吗? 一个线程执行了多长时间? 某个线程执行的时候我们期望的数据是否已经赋值了呢? 没有办法知道,我们所能做的就是等待这个多线程任务完成。 但+/可以轻松获取多线程操作的结果,如果等待时间过长,没有获取到需要的数据,可以取消线程的任务。

线程阻塞的原因是什么

阻塞是指暂停线程的执行,等待某个条件的发生(比如某个资源准备好)。 学过操作系统的同学一定很熟悉。 Java提供了大量的方法来支持阻塞。 我们来一一分析。

方法说明 sleep()sleep() 允许您指定一段以毫秒为单位的时间作为参数。 它导致线程在指定时间内进入阻塞状态,无法获得CPU时间。 一旦指定的时间过去,线程重新进入可执行状态。 通常,sleep()用在等待某个资源准备好时:测试发现不满足条件后,让线程阻塞一段时间,然后重新测试,直到满足条件。 ()和()一起使用,()会使线程进入阻塞状态,并且不会自动恢复。 必须调用其相应的()才能使线程重新进入可执行状态。 通常,()和()用于等待另一个线程产生结果时:测试后发现结果还没有产生,则线程被阻塞,等另一个线程产生结果后,调用()恢复它。 yield()yield()导致当前线程放弃当前分配的CPU时间,但不会导致当前线程阻塞,即线程仍处于可执行状态,随时可能再次分配CPU时间。 调用yield()的效果相当于调度程序认为该线程已经执行了足够的时间,可以转移到另一个线程。 wait() 和 () 这两个方法一起使用。 wait() 使线程进入阻塞状态。 它有两种形式,一种允许指定一段以毫秒为单位的时间作为参数,另一种则没有参数。 前者在调用对应的()或者超过指定的时间时会重新进入可执行状态,而后者必须对应()的调用。

wait(),() 和 (),() 之间的区别

乍一看它们与 () 和 () 方法对没有什么不同,但实际上它们完全不同。 核心区别在于,上面介绍的所有方法在阻塞时都不会释放占用的锁(如果被占用的话),而这个相反的规则则相反。 上述核心差异导致了一系列细节差异。

首先,上面介绍的所有方法都属于类,但这对是直接从属于类的,即所有对象都有这对方法。 这乍一听似乎难以置信,但事实上这是很自然的。 由于这对方法在阻塞时需要释放占用的锁,而该锁被任何对象占有,因此调用任何对象的wait()方法都会导致线程阻塞。 并且对象上的锁被释放。 调用任何对象的 wait() 方法都会导致因调用该对象的 wait() 方法而阻塞的线程之一被解除阻塞(但直到获得锁后才会执行)。

其次,上面描述的所有方法都可以在任何位置调用,但这对方法必须在一个方法或块中调用。 原因也很简单。 只有在方法或者块中当前线程占用了锁,才可以释放锁。 。 同理,调用这对方法的对象上的锁也必须是当前线程拥有的,这样才能释放锁。 因此,这对方法调用必须放在一个方法或块中,该方法或块的锁定对象就是调用这对方法的对象。 如果不满足这个条件,程序仍然可以编译,但运行时会出现异常。

wait()和()方法的上述特点决定了它们经常与关键字一起使用。 如果将它们与操作系统的进程间通信机制进行比较,就会发现它们的相似之处:方法或块提供了与原始操作系统类似的方法。 语言的函数,它们的执行不会受到多线程机制的干扰,而这对方法相当于block和(这对方法都声明为)。 它们的结合使得我们可以在操作系统上实现一系列精巧的进程间通信算法(如信号量算法),并用于处理各种复杂的线程间通信问题。

关于wait()和()方法最后两点:第一:调用()方法解除阻塞的线程是从调用对象的wait()方法阻塞的线程中随机选择的。 我们无法预测哪个线程将被解除阻塞。 会选择一个线程,所以编程时要小心,避免这种不确定性带来的问题。

第二:除了()之外,还有一个方法()也可以起到类似的作用。 唯一的区别是,调用 () 方法会一次性解除所有通过调用对象的 wait() 方法而阻塞的线程。 。 当然,只有获得锁的线程才能进入可执行状态。

说到阻塞,就不得不说到死锁。 简单分析一下,调用()方法和wait()方法而不指定超时时间可能会导致死锁。 不幸的是,Java不支持语言层面的死锁避免,我们在编程中必须小心避免死锁。

上面我们分析了Java中线程阻塞的各种方法。 我们重点关注 wait() 和 () 方法,因为它们功能最强大,使用起来也最灵活,但这也导致它们效率较低且更容易出错。 在实际使用中,我们应该灵活运用各种方法,才能更好地达到我们的目的。

产生死锁的条件

1、互斥条件:一种资源一次只能被一个进程使用。

2.请求和保持条件:当一个进程因请求资源而被阻塞时,它将保留所获得的资源。

3、不剥夺条件:进程已经获得的资源在用完之前不能被强行剥夺。

4、循环等待情况:几个进程之间形成头尾循环等待资源关系。

为什么在同步块中调用 wait() 方法和 ()/() 方法?

这是 JDK 强制执行的。 wait()方法和()/()方法在调用之前都必须获得对象的锁。

wait()方法和()/()方法在放弃对象监视器时有什么区别?

wait()方法与()/()方法在放弃对象监视器时的区别在于,wait()方法立即释放对象监视器,而()/()方法则等待对象监视器的剩余代码线程在放弃对象之前完成执行。 监视器。

wait() 和 sleep() 之间的区别

这两个上面已经详细解释了,这里总结一下:

sleep() 来自类,wait() 来自类。 在调用sleep()方法期间,线程不会释放对象锁。而调用wait方法线程会释放对象锁

sleep()休眠后不出售系统资源,wait允许其他线程占用CPU

sleep()需要指定一个睡眠时间,时间到了就会自动唤醒。 而wait()需要与()或()配合使用

为什么wait,这些方法没有放在类中呢?

一个明显的原因是JAVA提供的锁是在对象级别而不是线程级别。 每个对象都有一个锁,它是通过线程获得的。 如果线程需要等待某些锁,那么调用对象中的 wait() 方法是有意义的。 如果类中定义了 wait() 方法,则线程正在等待哪个锁是不明显的。 简单来说,因为wait、and都是锁级别的操作,所以定义在类中是因为锁属于对象。

如何唤醒被阻塞的线程

如果线程由于调用wait()、sleep()或join()方法而被阻塞,可以中断线程并通过抛出来唤醒它; 如果线程遇到IO阻塞,你无能为力,因为IO是由操作系统实现的。 是的,Java代码没有办法直接联系操作系统。

什么是多线程上下文切换

多线程上下文切换是指将CPU控制权从一个已经运行的线程切换到另一个准备好等待获取CPU执行权的线程的过程。