Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Introduction to Jython, Part 2: Programming essentials

Barry Feigenbaum, Sr. Consulting IT Architect, IBM

Dr. Barry Feigenbaum is a member of the IBM Worldwide Accessibility Center, where he is part of team that helps IBM make its own products accessible to people with disabilities. Dr. Feigenbaum has published several books and articles, holds several patents, and has spoken at industry conferences such as JavaOne. He serves as an Adjunct Assistant Professor of Computer Science at the University of Texas, Austin.

Dr. Feigenbaum has more than 10 years of experience using object-oriented languages like C++, Smalltalk, the Java programming language, and Jython. He uses the Java language and Jython frequently in his work. Dr. Feigenbaum is a Sun Certified Java Programmer, Developer, and Architect.


Acknowledgements

I would like to acknowledge Mike Squillace and Roy Feigel for their excellent technical reviews of this tutorial.

Summary:  This is the second installment in a two-part tutorial designed to introduce you to the Jython scripting language. Part 1 covered the basics of Jython, including installation and setup, access options and file compilation, syntax and data types, program structure, procedural statements, and functions. In Part 2 you will delve into some of the more advanced aspects of working with this powerful scripting language, starting with an in-depth introduction to object-oriented programming with Jython. You'll also learn about topics essential to the mechanics of application development in any language, including debugging, string processing, and file I/O.

Date:  08 Apr 2004
Level:  Introductory

Activity:  44796 views
Comments:  

Java thread support in Jython

Java threads

The Java runtime makes extensive use of threads, which it uses to handle GUI events, to perform asynchronous I/O, to implement asynchronous processing, and so on.

It's easy to create Java threads in Jython: just create instances of java.lang.Thread and subclasses of java.lang.Runnable. For an example, see The GUI: fgui.py. You can also create threads out of Jython functions by using the thread module and functions of the following form:

start_new_thread(function, args)

-- and --

exit()

The start_new_thread function runs the function argument in a new Java thread, passing the args tuple value to the function. The exit function can be used in the thread to end it (generally as the target of an if statement).

Java synchronization

When developing multithreaded programs using Java or Jython threads, it is sometimes necessary to create synchronized functions (or methods). Synchronized functions are functions that can only be called from one thread at a time; meaning that other threads are prevented from entering the function until the first thread exits. Jython provides the synchronized module and two functions to create synchronized functions. The functions are of the following form:

make_synchronized(function)

-- and --

apply_synchronized(syncobj, function, pargs {, kwargs})

The make_synchronized function permanently synchronizes the function argument. The apply_synchronized function temporarily synchronizes on syncobj and then calls the function argument.


Example: Using make_synchronized

Using make_synchronized to signal events is quite straightforward, as shown below:

from synchronize import *
from java import lang

# define synchronization helpers

def waitForSignal (monitor):
    """ Wait until the monitor is signaled. """
    lang.Object.wait(monitor)
# replace with synchronized version; syncs on 1st argument
waitForSignal = make_synchronized(waitForSignal)

def notifySignal (monitor):
    """ Signal monitor. """
    lang.Object.notifyAll(monitor)
# replace with synchronized version; syncs on 1st argument
notifySignal = make_synchronized(notifySignal)

class Gui:           # GUI support
    :
    def doExit (self):
        self.visible = 0
        notifySignal(self)

if __name__ == "__main__":     # main code
    : 
    gui = Gui()
    : 
    print "Waiting until GUI exit requested..."
    waitForSignal(gui)
    print "Done"


A Jython threading example

Here's an example of the use of Jython threads. The example shows a set of producer and consumer threads sharing access to a common buffer. We'll start with the definition of the shared buffer, as shown below.

""" A Jython Thread Example. """

from java import lang 
from synchronize import *
from thread import start_new_thread
from sys import stdout

def __waitForSignal (monitor):
    apply_synchronized(monitor, lang.Object.wait, (monitor,))

def __signal (monitor):
    apply_synchronized(monitor, lang.Object.notifyAll, (monitor,))

def __xprint (stream, msg):
    print >>stream, msg

def xprint (msg, stream=stdout):
    """ Synchronized print. """
    apply_synchronized(stream, __xprint, (stream, msg))

class Buffer:
    """ A thread-safe buffer. """

    def __init__ (self, limit=-1):
        self.__limit = limit    # the max size of the buffer
        self.__data = []
        self.__added = ()       # used to signal data added
        self.__removed = ()     # used to signal data removed

    def __str__ (self):
        return "Buffer(%s,%i)" % (self.__data, self.__limit)

    def __len__ (self):
        return len(self.__data)

    def add (self, item):
        """ Add an item. Wait if full. """
        if self.__limit >= 0:
            while len(self.__data) > self.__limit:
                __waitForSignal(self.__removed)
        self.__data.append(item);
        xprint("Added: %s" % item)
        __signal(self.__added)

    def __get (self):
        item = self.__data.pop(0)
        __signal(self.__removed)
        return item

    def get (self, wait=1):
        """ Remove an item. Wait if empty. """
        item = None
        if wait:
            while len(self.__data) == 0:
                __waitForSignal(self.__added)
            item = self.__get()
        else:
            if len(self.__data) > 0: item = self.__get()
        xprint("Removed: %s" % item)
        return item
    get = make_synchronized(get)
    


Producer and consumer definitions

The next step in the example is to take a look at the producer and consumer definitions, shown here:

class Producer:
    def __init__ (self, name, buffer):
        self.__name = name
        self.__buffer = buffer

    def __add (self, item):
        self.__buffer.add(item)

    def __produce (self, *args):
        for item in args:
            self.__add(item)

    def produce (self, items):
        start_new_thread(self.__produce, tuple(items))

class Consumer:
    def __init__ (self, name, buffer):
        self.__name = name
        self.__buffer = buffer

    def __remove (self):
        item = self.__buffer.get()
        return item

    def __consume (self, count):
        for i in range(count):
            self.__remove()

    def consume (self, count=1):
        start_new_thread(self.__consume, (count,))


An trial run of the threading example

And finally, here's a trial run of the example code:

# all producers and consumer share this one
buf = Buffer(5)    

p1 = Producer("P1", buf)
p2 = Producer("P2", buf)
p3 = Producer("P3", buf)
p4 = Producer("P4", buf)
c1 = Consumer("C1", buf)
c2 = Consumer("C2", buf)

# create 6 items
p1.produce(["P1 Message " + str(i) for i in range(3)])
p2.produce(["P2 Message " + str(i) for i in range(3)])

# consume 20 items
for i in range(5):
    c1.consume(2)
    c2.consume(2)

# create 20 more items
p3.produce(["P3 Message " + str(i) for i in range(10)])
p4.produce(["P4 Message " + str(i) for i in range(10)])

# consume 4 items
c1.consume(2)
c2.consume(2)

# let other threads run
lang.Thread.currentThread().sleep(5000)

xprint("Buffer has %i item(s)left" % len(buf))


Output of the example

The producer consumer example produces the following results (wrapped to two columns to save space):

Added: P1 Message 0       Added: P3 Message 7       
Added: P1 Message 1       Removed: P3 Message 7     
Added: P1 Message 2       Added: P3 Message 8       
Added: P2 Message 0       Removed: P3 Message 8     
Added: P2 Message 1       Added: P3 Message 9       
Added: P2 Message 2       Removed: P3 Message 9     
Removed: P1 Message 0     Added: P4 Message 0       
Removed: P1 Message 1     Removed: P4 Message 0     
Removed: P1 Message 2     Added: P4 Message 1       
Removed: P2 Message 0     Removed: P4 Message 1     
Removed: P2 Message 1     Added: P4 Message 2       
Removed: P2 Message 2     Removed: P4 Message 2     
Added: P3 Message 0       Added: P4 Message 3       
Removed: P3 Message 0     Removed: P4 Message 3     
Added: P3 Message 1       Added: P4 Message 4       
Removed: P3 Message 1     Added: P4 Message 5       
Added: P3 Message 2       Added: P4 Message 6       
Removed: P3 Message 2     Added: P4 Message 7       
Added: P3 Message 3       Added: P4 Message 8       
Removed: P3 Message 3     Added: P4 Message 9       
Added: P3 Message 4       Removed: P4 Message 4     
Removed: P3 Message 4     Removed: P4 Message 5     
Added: P3 Message 5       Removed: P4 Message 6     
Removed: P3 Message 5     Removed: P4 Message 7     
Added: P3 Message 6       Buffer has 2 item(s)left  
Removed: P3 Message 6

6 of 15 | Previous | Next

Comments



static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=131936
TutorialTitle=Introduction to Jython, Part 2: Programming essentials
publish-date=04082004
author1-email=feigenba@us.ibm.com
author1-email-cc=jaloi@us.ibm.com