`
yiminghe
  • 浏览: 1432471 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

java与python多线程wait操作比较

阅读更多

由于主要用java做web开发,除了以前的在线聊天试验 ,对于Object下的wait与notify确实很少使用,并且java中wait与notify都是native的方法,也只能看看api doc,注意下使用事项,总觉得不很踏实,一般来说对于多线程同步问题,最基本的思想就是加锁,其他一切同步机制实际上都是由锁来构造的,那么wait与notify也应该能用锁来实现,近来学习python知道,python中最基本的同步机制就是锁 (Lock),用C实现,而wait与notify则是在锁的基础上用python自身实现,定义在lib/threading.py的Condition类中,看完之后终于对wait机制有了更深刻的理解。

 

 

java

 

简单介绍一下java中的wait以及notify:

首先可以这样理解,每个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后代码。

 

 

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实现了经典的生产者与消费者模型

 

java:

 

class Q {
    int n;
    boolean valueSet = false;

    /*
   如果不同步获得monitor,则会抛出java.lang.IllegalMonitorStateException
    */
    /*
      同步方式1:By executing a synchronized instance method of that object.
     */
    synchronized int get() {

        if (!valueSet)
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        System.out.println("Got: " + n);
        valueSet = false;
        notify();
        return n;
    }

    /*
   如果不同步获得monitor,则会抛出java.lang.IllegalMonitorStateException
    */
    void put(int n) {
        /*
        同步方式2:By executing the body of a synchronized statement
     *     that synchronizes on the object.
         */
        synchronized (this) {

            if (valueSet)
                try {
                    wait();
                } catch (InterruptedException e) {
                    System.out.println("InterruptedException caught");
                }
            this.n = n;
            valueSet = true;
            System.out.println("Put: " + n);
            notify();
        }
    }
}

class Producer implements Runnable {
    Q q;

    Producer(Q q) {
        this.q = q;
        new Thread(this, "Producer").start();
    }

    public void run() {
        int i = 0;
        while (i < 7) {
            q.put(i++);
        }
    }
}

class Consumer implements Runnable {
    Q q;

    Consumer(Q q) {
        this.q = q;
        new Thread(this, "Consumer").start();
    }

    public void run() {
        int i = 0;
        while (i < 7) {
            q.get();
            i++;
        }
    }
}

class WaitTest {
    public static void main(String args[]) {
        Q q = new Q();
        new Producer(q);
        new Consumer(q);

    }
}
 

 

python:

 

# -*- coding: utf-8 -*-  
import threading
class Q(object):
    def __init__(self):
        self.n=0
        self.valueSet=False
        #相对于java,这里的要自己声明
        self.cv=threading.Condition()
        
    def get(self):
        cv=self.cv
        #先得到锁
        cv.acquire()
        if not self.valueSet:
            cv.wait()
        print "Got:",self.n
        self.valueSet=False
        cv.notify()
        #放弃锁
        cv.release()
        return self.n
        
    def put(self,n):
        cv=self.cv
        #先得到锁
        cv.acquire()
        if self.valueSet:
            cv.wait()
        self.n=n;
        self.valueSet=True
        print "Put:",n
        #放弃锁
        cv.notify()
        cv.release()
        
class Producer(threading.Thread):
    def __init__(self,q):
        threading.Thread.__init__(self)
        self.q=q
        self.start()
        
    def run(self):
        i=0
        while i<7:
            i+=1
            self.q.put(i)    
            
class Consumer(threading.Thread):
    def __init__(self,q):
        threading.Thread.__init__(self)
        self.q=q
        self.start()
        
    def run(self):
        i=0
        while i<7:
            i+=1
            self.q.get()
            
if __name__=="__main__":
    q=Q()
    Producer(q)
    Consumer(q)
        
 
0
2
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics