Apache Jakarta Commons(c) Reusable Java Components
Authors: Iverson W.
Published year: 2006
Pages: 38-39/137
Buy this book on amazon.com >>


Object Factory Example

The object factory, shown in Listing 5-2, implements the PoolableObjectFactory interface. The two key methods implemented are makeObject() and validateObject() . The factory always returns false for an invalid object because when a thread enters a finished state, it cannot be reused. Because the pool is configured to always test on return (as shown in Listing 5-1), this means that the WorkerThread will be removed when completed.

Listing 5-2. Thread Factory
package com.cascadetg.ch05;

import org.apache.commons.pool.PoolableObjectFactory;

public class WorkerThreadFactory implements PoolableObjectFactory
{
    /** Keeps track of the currently created thread. */
    public int currentThread = 0;

    /**  Create and name the thread.  Naming the thread is very
     * helpful when trying to debug multi-threaded applications.
     */
    public Object makeObject() throws Exception
    {
        WorkerThread temp = new WorkerThread();
        temp.setName("Worker Thread #" + currentThread++);
        return temp;
    }

    /** We aren't reusing threads, so we always return false here,
     * causing the pool to remove this thread from the pool and
     * create a new object using the makeObject() method.
     */
    public boolean validateObject(Object arg0) { return false; }

    public void destroyObject(Object arg0) throws Exception  { }
    public void activateObject(Object arg0) throws Exception { }
    public void passivateObject(Object arg0) throws Exception { }
}


Worker Thread

Listing 5-3 shows our worker thread. The default implementation merely counts to 1,000, yielding every count. This is overly aggressive , but it does allow the system to remain highly responsive to other threads during execution. It's easy to imagine changing the behavior of this worker thread to do something more computationally complexfor example, when used in conjunction with the networking capabilities shown in Chapter 4, "Net" and this chapter, parallel execution could well be much faster and easier.

The implementation shown in Listing 5-3 drops out of the run() method when complete, rendering the thread no longer reusable. It would be possible to create a reusable WorkerThread instead of completing and dropping out of the run() method, the thread could instead have two statesa busy state and an idle state, with the thread returning itself to the pool when switching from the busy state to idle.

Listing 5-3. Worker Thread
package com.cascadetg.ch05;

import org.apache.commons.pool.ObjectPool;

public class WorkerThread extends Thread
{
    // The total amount of work done by the threads.
    static public long totalUnits = 0;
    // The number of times the thread should look over a counter
    // (this is our definition of work)
    private int counter = 1000;

    // When the thread is done, it returns itself to the pool.
    private ObjectPool hostPool = null;
    // Used to indicate that a thread, when completed, is no longer
    // useful.
    public boolean valid = true;

    public void setPool(ObjectPool myPool)
    {
        hostPool = myPool;
    }

    public void run()
    {
        // Loop over a counter, and yield each time to allow other
        // threads to execute.  In a "real" app, you wouldn't need
        // to yield anywhere near this often.
        for (int i = 0; i < counter; i++)
        {
            totalUnits++;
            yield();
        }
        try
        {
            // We synchronize on the pool to avoid possible
            // threading problems, and return our object.
            synchronized (hostPool)
            {
                this.valid = false;
                hostPool.returnObject(this);
            }
        } catch (Exception e)
        { e.printStackTrace(); }
    }
}

Finally, Listing 5-4 shows an example of the output of this application. Paying close attention to the output, we can see that in this particular case, a non-parallel approach has the best timing. This is to be expected in a CPU- dependent, single system environment, but in environments involving potentially slow resources (such as network access), the results may be quite different.

Listing 5-4. Sample Output
Starting 30/30
Total created threads:30
Seconds Elapsed: 0.191
Completed:            30000
units/second:       157068.06

Starting 100/100
Total created threads:100
Seconds Elapsed: 0.801
Completed:            100000
units/second:       124843.945

Starting 1000/1000
Total created threads:1000
Seconds Elapsed: 9.794
Completed:            1000000
units/second:       102103.33

Starting 1000/2000
Total created threads:2000
Seconds Elapsed: 19.127
Completed:            2000000
units/second:       104564.23

Starting 1/3000
Total created threads:3000
Seconds Elapsed: 5.398
Completed:            3000000
units/second:       555761.44

Starting 10/3000
Total created threads:3000
Seconds Elapsed: 6.85
Completed:            3000000
units/second:       437956.22

Starting 30/3000
Total created threads:3000
Seconds Elapsed: 7.641
Completed:            3000000
units/second:       392618.78

Starting 1000/3000
Total created threads:3000
Seconds Elapsed: 28.471
Completed:            3000000
units/second:       105370.375

Most efficient @ 555761.44
(1/3000)
Done.

Apache Jakarta Commons(c) Reusable Java Components
Authors: Iverson W.
Published year: 2006
Pages: 38-39/137
Buy this book on amazon.com >>

Similar books on Amazon