wait()和sleep()
简单来说,都会进入阻塞状态,wait方法,直接释放锁,也就是对象的监视器,等待被唤醒,需要同Synchronized配合使用,sleep方法,不释放锁,等一定时间。
补充:
-
定义和所属类
-
wait()
方法:wait()
方法是Object
类中的方法。它用于使当前线程进入等待状态,直到其他线程调用该对象的notify()
或notifyAll()
方法来唤醒它。这个方法通常在同步代码块或同步方法中使用,因为它需要获取对象的锁才能调用。 -
sleep()
方法:sleep()
方法是Thread
类中的静态方法。它会使当前线程暂停执行一段时间,这个时间是由方法参数指定的(以毫秒为单位)。线程在睡眠期间不会释放它已经获取的锁(如果有的话)。
-
-
使用场景和目的
-
wait()
方法:-
线程间通信与协作:主要用于实现线程之间的协调和通信,特别是在共享资源的多线程环境中。例如,在生产者 - 消费者模型中,消费者线程在发现共享缓冲区为空时,可以调用
wait()
方法等待生产者生产数据。生产者生产完数据后,通过调用notify()
或notifyAll()
方法唤醒等待的消费者线程。 -
等待条件满足:当一个线程需要等待某个对象的状态满足特定条件才能继续执行时使用。比如,等待一个队列对象非空、等待一个任务完成的标志被设置等情况。
-
-
sleep()
方法:-
简单的时间延迟:用于在不需要复杂的线程间交互的情况下,使线程暂停一段时间。例如,在一个定时任务中,线程完成一次任务后,通过
sleep()
方法暂停一段时间,然后再执行下一次任务。 -
模拟长时间操作或调整执行节奏:在测试环境中,可以用
sleep()
方法来模拟一些耗时的操作,如网络延迟、文件读取时间等。在一些需要控制线程执行速度的场景下,也可以使用sleep()
来调整线程的执行节奏。
-
-
-
对锁的处理方式
-
wait()
方法:当一个线程调用wait()
方法时,它会释放当前对象的锁。这是非常重要的一点,因为这样其他线程就可以获取该对象的锁并修改对象的状态,从而有可能使等待的条件得到满足。例如,在一个同步方法中,线程调用wait()
后,其他线程就可以进入这个同步方法来改变对象的状态。 -
sleep()
方法:线程在执行sleep()
方法期间不会释放已经获取的锁。这意味着如果线程在持有锁的情况下进入睡眠状态,其他需要该锁的线程会被阻塞,直到睡眠的线程醒来并释放锁。这种行为可能会导致性能问题或者死锁情况,需要谨慎使用。
-
-
被唤醒后的行为和执行顺序
-
wait()
方法:当线程被notify()
或notifyAll()
方法唤醒后,它会重新尝试获取对象的锁。如果成功获取锁,线程会从wait()
方法调用后的位置继续执行。需要注意的是,notify()
方法只会随机唤醒一个等待在该对象上的线程,而notifyAll()
方法会唤醒所有等待的线程,但是这些被唤醒的线程需要竞争锁,只有获取到锁的线程才能继续执行。 -
sleep()
方法:线程睡眠结束后,会从sleep()
方法调用后的位置继续执行,不需要重新获取锁(因为它在睡眠期间没有释放锁)。如果睡眠时间到了,但是当前线程没有获取到 CPU 资源,它会继续等待 CPU 分配时间片,一旦获得时间片就会继续执行。
-
wait 和 sleep 是否会触发锁的释放以及 CPU 资源的释放
Object.wait()方法,会释放锁资源以及 CPU 资源。
Thread.sleep()方法,不会释放锁资源,但是会释放 CPU 资源。
wait
wait()方法是让一个线程进入到阻塞状态,而这个方法必须写在一个 Synchronized 同步代码块里面。
因为 wait/notify 是基于共享内存来实现线程通信的工具,这个通信涉及条件的竞争,所以在调用这两个方法之前必须竞争锁资源。
(wait,释放已经获取的对象锁,然后进入等待状态,直到被其他线程唤醒,涉及对象监视器状态的改变;notify和notifyAll,用于通知正在等待该对象的其他线程,它们的操作同样涉及对象的监视器状态的改变,所以需要竞争锁资源)
当线程调用 wait 方法的时候,表示当前线程的工作处理完了,意味着让其他竞争同一个共享资源的线程有机会去执行。
但前提是其他线程需要竞争到锁资源,所以 wait 方法必须释放锁,否则就会导致死锁的问题。
sleep
只是让一个线程单纯进入睡眠状态,这个方法并没有强制要求加synchronized 同步锁。
而且从它的功能和语义来说,也没有这个必要。
当然,如果是在一个 Synchronized 同步代码块里面调用这个 Thread.sleep,也并不会触发锁的释放
最后,凡是让线程进入阻塞状态的方法,操作系统都会重新调度实现 CPU 时间片切换,这样设计的目的是提升 CPU 的利用率,所以都会释放CPU资源
-
yield()方法仅释放 CPU 执行权 , 锁仍然占用 , 线程会被放入就绪队列 ,会在短时间内再次执行。
为什么 wait() 方法不定义在 Thread 中?sleep() 方法为何定义在 Thread 类?
wait()
方法定义在 Object
类中,而不是 Thread
类中,这与 Java 的同步机制和对象锁管理息息相关
wait
-
与对象锁机制的紧密关联
在 Java 中,线程同步是基于对象级锁的,每个对象都有一个与之关联的监视器(monitor)。当线程想要进入某个同步代码块时,它必须首先获得该对象的锁。而 wait() 方法的设计目的是让线程在释放该对象的锁的同时,进入等待状态,等待其他线程的通知。
因为 wait() 与对象的锁机制密切相关,它操作的对象的监视器锁,而不是线程本身。因此,将 wait() 方法定义在 Object 类中更为合理,因为它本质上是针对对象锁的操作,而不是线程的行为。
-
线程在对象上等待
调用 wait()
时,线程是在某个对象上等待,即它等待的是某个对象的锁状态或条件的变化。这与线程自身的状态无关,而是依赖于对象的状态。因此,wait()
应该在 Object
类中,而不是在 Thread
类中,因为它的操作对象是锁定的资源,而不是线程。
sleep
与 wait()
不同,sleep()
方法定义在 Thread
类中,这是因为 sleep()
控制的是线程本身的行为,而不是对象的状态。
-
sleep()
控制线程的执行节奏
sleep()
方法的作用是让当前线程暂停执行一段时间。它的功能仅仅是控制线程的休眠时间,而不涉及线程间的通信或对象锁。因此,将它定义在 Thread
类中是非常合适的,因为它直接影响线程的生命周期。
-
sleep()
不涉及对象锁
sleep()
与对象的锁机制无关,线程调用 sleep()
后不会释放它所持有的任何锁。相反,线程在 sleep()
期间继续持有锁,只是暂停执行。因此,sleep()
是一个纯粹的线程行为控制方法,应该定义在 Thread
类中,而不是 Object
类中。
-
静态方法设计
sleep()
是 Thread
类的静态方法,这意味着它影响的是当前正在运行的线程。无论哪个线程调用 Thread.sleep()
,都表示当前线程需要休眠。将其定义为静态方法避免了通过特定的线程实例来调用,简化了使用方式。
补充:
-
为什么
wait()
方法不定义在Thread
类中?-
从功能角度:
-
wait()
方法的主要作用是让当前线程进入等待状态,直到其他线程调用notify()
或notifyAll()
方法来唤醒它。这个方法是和对象的监视器(monitor)机制紧密相关的,用于实现线程之间的协作和同步。它实际上是用于控制对象的访问权限,而不是直接控制线程的行为。例如,在一个生产者 - 消费者模型中,生产者线程和消费者线程共享一个缓冲区对象。当缓冲区为空时,消费者线程调用wait()
方法等待生产者生产数据,这个等待操作是基于缓冲区对象的状态,而不是线程本身的一个固有行为。
-
-
从设计理念角度:
-
Java 的多线程设计中,
Object
类是所有类的根类。将wait()
方法定义在Object
类中,可以让所有的对象都具备这种等待 - 唤醒的协作机制。这样的设计使得任何对象都可以作为锁对象,并且在其上调用wait()
和notify()
等方法来实现线程间的同步。如果wait()
方法定义在Thread
类中,就会限制这种同步机制只能在特定的线程相关对象上使用,不符合 Java 的面向对象和通用的多线程协作设计理念。
-
-
从使用场景角度:
-
一个线程可能会在多个对象上等待,比如在一个复杂的多线程应用程序中,一个线程可能需要等待多个共享资源(不同的对象)的状态变化。如果
wait()
方法在Thread
类中,就很难方便地实现这种基于不同对象的等待操作。而通过将wait()
方法放在Object
类中,线程可以根据需要针对不同的对象进行等待操作,只需要获取对象的锁,就可以调用wait()
方法进入等待状态。
-
-
-
为什么
sleep()
方法定义在Thread
类?-
从功能角度:
-
sleep()
方法的主要功能是让当前线程暂停执行一段时间。这是一种直接作用于线程本身的操作,它不涉及对象的监视器和线程间的协作同步机制。例如,一个简单的定时任务线程,它需要每隔一段时间执行一次任务,就可以使用sleep()
方法来暂停自己的执行,等待下一个时间点到来。这种暂停操作是线程自身的行为,和任何特定的对象状态无关。
-
-
从设计理念角度:
-
把
sleep()
方法定义在Thread
类中符合封装的原则,它明确地表示这是一个与线程自身运行状态相关的操作。这样的设计使得开发者能够直观地理解sleep()
方法是用于控制线程本身的暂停,而不是与对象之间的同步相关。如果sleep()
方法也像wait()
方法一样定义在Object
类中,会容易引起混淆,因为从功能上看,它和对象之间的同步等待没有直接关系。
-
-
从使用场景角度:
-
在实际的开发中,我们经常需要在不依赖于任何特定对象的情况下,暂停一个线程的执行。例如,在一个多线程的服务器应用程序中,一个后台线程可能需要定期检查一些系统资源的使用情况,它可以使用
sleep()
方法来设置检查的间隔时间,而不需要和其他对象的等待 - 唤醒机制关联在一起。将sleep()
方法定义在Thread
类中方便了这种与对象无关的、纯粹的线程暂停操作。
-
-
线程的 sleep()方法和 yield()方法有什么区别?
① sleep()方法给其他线程运行机会时不考虑线程的优先级 ,因此会给低优先级的线程以 运行的机
会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;
② 线程执行 sleep()方法后转入阻塞( blocked) 状态 , 而执行 yield()方法后转入就绪
( ready )状态;
③ sleep()方法声明抛出 Interrupted Exception , 而 yield()方法没有声明任何异常;
④ sleep()方法比 yield()方法( 跟操作系统 CPU 调度相关)具有更好的可移植性。
标签:对象,理解,线程,sleep,方法,类中,wait From: https://blog.csdn.net/qq_62097431/article/details/144454958