wait 和notify的应用场景
在学习wait,notify之前首先需要解释java中wait()和notify()的应用场景。wait和notify提供了对多个线程之间的等待和通知操作。例如抓取站外多张图片通常会通过多个thread同时进行,但主线程需要等到这批数据返回的结果。
多线程操作通常都有提交者(submiter)和执行者(executor),java通过concurrent包提供的Executors提供了很好的支持,如果不通过wait和notify,只能通过轮循来实现,实际上是很低效的:
看看之前我们网站的fetch实现方式:
def fetch(self, url): for i in range(2): title, images = build_fetch(url).fetch(url) if images: break if images: images = images[:150] self._finished = False self._total = len(images) current = 0 while current < self._total: self.pool.queueTask(self.check_image, images[current:current + self._per_check], self.collect_image) current = current + self._per_check from time import sleep # 等待抓取完毕 while not self._finished: sleep(0.05) pass return title, self._urls
java
首先可以这样理解,每个object实际上自身和一个monitor(锁)关联,object.wait(timeout) :使当前线程放弃object的锁并等待,除非其它线程调用了object.notify()或者object.notifyAll(),或者使等待线程中断,或者等待了timeout时间。
object.notify():随机唤醒一个等待在object的线程 ,该线程和其他活动线程一起争夺object的锁。
object.notifyAll():唤醒所有等待在object的线程 ,线程和其他活动线程一起争夺object的锁。
根据 java api doc ,使用wait,notify注意事项:
1. 调用线程必须已经获得了object的锁,即在synchronized方法或者synchronized(object){}语句块中调用。
2. 调用线程被唤醒后实际上并不会立即执行后续操作,它要先和其它活动线程竞争获得当前对象的锁,得到对象锁后才能接着执行wait后代码。
下面是一个例子:
public class Tester3 { public synchronized void take() { System.out.println("take"); try { Thread.currentThread().sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void put() { System.out.println("put"); } /** * @param args */ public static void main(String[] args) { final Tester3 tester = new Tester3(); Thread t = new Thread(new Runnable() { @Override public void run() { System.out.println("take begin"); tester.take(); System.out.println("take end"); } }); t.start(); t = new Thread(new Runnable() { @Override public void run() { System.out.println("put begin"); tester.put(); System.out.println("put end"); } }); t.start(); } }
输出(put必须等到get释放锁之后才能被执行):
take begin
put begin
take
take end
put
put end
python
python对象没有隐式的和一个锁关联,且python中的 wait,notify是由python语言自身利用锁(Lock)实现,实现类为Condition,但是概念思想上是和java保留一致,如果要模拟 java的话,只需创建python对象时,显式将一个Condition实例赋给创建对象的一个成员属性,那么可以对应java中的doc来看一下 python的实现:
threading.py Condition类:
1。wait,notify必须在获得当前对象锁的前提下:
def wait(self, timeout=None): if not self._is_owned(): raise RuntimeError("cannot wait on un-aquired lock") ....... def notify(self, n=1): if not self._is_owned(): raise RuntimeError("cannot notify on un-aquired lock") .......
可见在wait,notify时都要进行检查,其中self._is_owned()正是判断调用线程是否获得了Condition的内置锁,也即java中对象monitor的概念。
2.wait调用后会使当前线程放弃已经获得对象锁:
def wait(self, timeout=None): ..... saved_state = self._release_save()
其中 self._release_save正是进行了放弃Condition内置锁的操作,也对应着java先放弃对象monitor的概念
3.wait 使当前线程等待的实现
java doc说明:将当前线程加入object的waitset,然后等待。
python实现为:当前线程在一个新建锁上等待,把该锁加入到condition的等待数组中,线程等待锁的release
def wait(self, timeout=None): ... #新建一把锁 waiter = _allocate_lock() #现获得一次,后面再获得就阻测 waiter.acquire() #记录等待 self.__waiters.append(waiter) ..... if timeout is None: #在该锁上等待 waiter.acquire() if __debug__: self._note("%s.wait(): got it", self)
4.notify唤醒等待线程实现
同java不同,java notify唤醒的线程不能确定,而python则能确定,一定是第一个调用wait的线程被唤醒,即为先进先出的队列结构。
对于python为:release __waiters等待数组的第一个锁,对应的等待线程即可重新开始在wait函数内运行:
def notify(self, n=1): .... waiters = __waiters[:n] for waiter in waiters: #锁释放,意味着等待锁的对应线程可是从wait函数运行 waiter.release() try: __waiters.remove(waiter) except ValueError: pass
5.唤醒线程和其他活动线程争夺对象锁
唤醒线程并不是立刻从wait()返回开始它的实际操作,而是要先争夺conditon的内置锁,即java的object monitor:
def wait(self, timeout=None): #等待在新建锁上 if timeout is None: waiter.acquire() #新建锁释放了,但是要先获得condition内置锁才能返回 self._acquire_restore(saved_state)
6.wait的超时处理与notifyAll 略
实例:
分别用java与python实现了经典的生产者与消费者模型
原文:http://yiminghe.iteye.com/blog/673379
相关推荐
本压缩包文件"python多线程.rar"涵盖了多线程的基础知识,包括线程同步、锁的使用、死锁与可重入锁的概念、条件变量、队列同步以及线程间通信和线程管理。 1. **多线程基本概念**:Python中的多线程允许同时执行多...
尽管文档标题与内容存在不一致(标题提及了“Python多线程编程的实践指南”而内容却涉及到了Matlab),这里我们将聚焦于Python多线程编程的相关知识点展开详细讨论。 ### Python多线程编程的实践指南 #### 一、多...
在Python编程中,多线程同步是处理并发执行的关键,主要目的是确保共享资源的安全访问,避免数据不一致性和竞态条件。以下四种方法是Python中实现多线程同步的常见方式: 1. **锁机制(Lock)** - **Lock** 类是...
多线程在Java、C++、Python等编程语言中都有广泛的应用。本篇文章将深入探讨多线程执行任务的具体实现方式。 一、线程的概念与优势 线程是操作系统分配CPU时间的基本单元,一个进程可以包含一个或多个线程。相比...
3. **线程间通信**:Java的wait(), notify()和notifyAll()方法,Python的`Condition`对象,用于线程间的信号传递。 **线程优先级** 1. **线程优先级**:不同线程可以设置不同的优先级,优先级高的线程更有可能获得...
在Java、Python、C++等编程语言中,都有内置的多线程支持。通过多线程,我们可以充分利用多核处理器的优势,提高程序的响应速度和整体效率。 在Java中,创建线程有多种方式: 1. 继承`Thread`类:自定义一个类继承...
在Java、C#、Python等语言中,都有内置的多线程支持。 多线程的工作原理主要包括以下几个方面: 1. **线程创建**:创建新线程通常通过调用特定函数或方法完成,如Java中的`Thread`类或`Runnable`接口,C#的`Thread`...
在Java中,有wait()、notify()和notifyAll()方法,以及BlockingQueue接口。线程通信有助于协调不同线程的工作,确保程序按预期执行。 **死锁** 死锁是多线程编程中的一种严重问题,发生在两个或更多线程互相等待...
2. 单线程与多线程:单线程程序只有一个执行流,而多线程程序则可以同时处理多个任务,提高了程序的并发性。 3. 并发与并行:并发是指在一段时间内多个任务交替执行,而并行是指在同一时刻多个任务同时执行。多线程...
本文实例讲述了python多线程高级锁condition简单用法。分享给大家供大家参考,具体如下: 多线程编程中如果使用Condition对象代替lock, 能够实现在某个事件触发后才处理数据, condition中含有的方法: – wait:线程...
在Java、Python、C#等编程语言中,都有内置的多线程支持。 描述中提到“可以单独执行一个线程,也可以多个线程同时执行”,这涉及到线程的创建和管理。在Java中,可以使用Thread类或者Runnable接口创建线程,Python...
总结来说,Python多线程同步在文件读写控制中的应用主要是为了避免并发访问造成的数据不一致。通过使用线程锁或其他同步机制,我们可以确保文件操作的顺序性,从而保证程序的正确性和数据的完整性。在编写多线程程序...
例如,Java的`wait()`、`notify()`和`notifyAll()`方法用于线程间通信,而Python的`queue`模块提供了线程安全的队列结构。 在实际开发中,我们还需要关注线程池的概念。线程池预先创建了一组线程,当需要执行新任务...
线程通信则是线程间传递信息的方式,如Java中的wait()、notify()和notifyAll()方法,Python中的queue模块等。 **六、死锁** 当两个或更多线程相互等待对方释放资源而无法继续执行时,就会发生死锁。防止和解决死锁...
在Python多线程编程中,正确同步线程间的操作非常重要。通过锁机制可以实现互斥访问公共资源,防止数据竞争等问题,但仅靠锁机制难以解决所有同步问题,特别是复杂情况下可能出现的死锁问题。Python中的Condition...
Java 提供了多种线程操作方法,例如 wait() 方法使线程等待,notify() 方法唤醒等待线程,interrupt() 方法中断线程等。 同步与死锁是多线程中需要注意的两个问题。同步是指多个线程同时访问共享资源时,需要使用锁...
总结来说,`threading.Condition` 在 Python 的多线程编程中扮演着重要角色,它为开发者提供了一种灵活的方式来控制线程何时执行,确保在正确的时间进行数据的生产和消费,从而避免并发问题。无论是 Python2 还是 ...
9. **多线程**:Thread类和Runnable接口,同步机制(synchronized关键字、wait/notify等)。 10. **反射机制**:动态获取类信息,创建对象,调用方法的能力。 【Python100道题】可能涵盖Python语言的各种基础到...
8. **多线程**:线程的创建、同步、通信方法,如synchronized关键字,wait(), notify(), join()等。 9. **反射机制**:利用反射动态地获取类的信息并操作对象。 10. **JVM内存模型**:了解堆、栈、方法区等内存...
在Java、Python、C#等编程语言中,都有内置的多线程支持。 在“多线程控制红绿灯变化”的实现中,我们可能使用到的关键概念和技术包括: 1. **线程同步**:为了确保红绿灯交替的正确性,需要对线程进行同步,防止...