O'Reilly logo

Java Web Services: Up and Running by Martin Kalin

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Multithreading the Endpoint Publisher

In the examples so far, the Endpoint publisher has been single-threaded and, therefore, capable of handling only one client request at a time: the published service completes the processing of one request before beginning the processing of another request. If the processing of the current request hangs, then no subsequent request can be processed unless and until the hung request is processed to completion.

In production mode, the Endpoint publisher would need to handle concurrent requests so that several pending requests could be processed at the same time. If the underlying computer system is, for example, a symmetric multiprocessor (SMP), then separate CPUs could process different requests concurrently. On a single-CPU machine, the concurrency would occur through time sharing; that is, each request would get a share of the available CPU cycles so that several requests would be in some stage of processing at any given time. In Java, concurrency is achieved through multithreading. At issue, then, is how to make the Endpoint publisher multithreaded. The JWS framework supports Endpoint multithreading without forcing the programmer to work with difficult, error-prone constructs such as the synchronized block or the wait and notify method invocations.

An Endpoint object has an Executor property defined with the standard get/set methods. An Executor is an object that executes Runnable tasks; for example, standard Java Thread instances. (The Runnable interface declares only one method whose declaration is public void run().) An Executor object is a nice alternative to Thread instances, as the Executor provides high-level constructs for submitting and managing tasks that are to be executed concurrently. The first step to making the Endpoint publisher multithreaded is thus to create an Executor class such as the following very basic one:

package ch01.ts;

import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;

public class MyThreadPool extends ThreadPoolExecutor {
    private static final int pool_size = 10;
    private boolean is_paused;
    private ReentrantLock pause_lock = new ReentrantLock();
    private Condition unpaused = pause_lock.newCondition();
    
    public MyThreadPool(){
       super(pool_size,        // core pool size
             pool_size,        // maximum pool size
             0L,               // keep-alive time for idle thread
             TimeUnit.SECONDS, // time unit for keep-alive setting
             new LinkedBlockingQueue<Runnable>(pool_size)); // work queue 
    }

    // some overrides
    protected void beforeExecute(Thread t, Runnable r) {
       super.beforeExecute(t, r);
       pause_lock.lock();
       try {
          while (is_paused) unpaused.await();
       }
       catch (InterruptedException e) { t.interrupt(); } 
       finally { pause_lock.unlock(); }
    }
    
    public void pause() {
       pause_lock.lock();
       try {
          is_paused = true;
       } 
       finally { pause_lock.unlock(); }
    }
    
    public void resume() {
       pause_lock.lock();
       try {
          is_paused = false;
          unpaused.signalAll();
       } 
       finally { pause_lock.unlock(); }
    }
}

The class MyThreadPool creates a pool of 10 threads, using a fixed-size queue to store the threads that are created under the hood. If the pooled threads are all in use, then the next task in line must wait until one of the busy threads becomes available. All of these management details are handled automatically. The MyThreadPool class overrides a few of the available methods to give the flavor.

A MyThreadPool object can be used to make a multithreaded Endpoint publisher. Here is the revised publisher, which now consists of several methods to divide the work:

package ch01.ts;

import javax.xml.ws.Endpoint;

class TimePublisherMT { // MT for multithreaded
    private Endpoint endpoint;

    public static void main(String[ ] args) {
        TimePublisherMT self = new TimePublisherMT();
        self.create_endpoint();
        self.configure_endpoint();
        self.publish();
    }
    private void create_endpoint() {
        endpoint = Endpoint.create(new TimeServerImpl());
    }
    private void configure_endpoint() {
        endpoint.setExecutor(new MyThreadPool());
    }
    private void publish() {
        int port = 8888;
        String url = "http://localhost:" + port + "/ts";
        endpoint.publish(url);
        System.out.println("Publishing TimeServer on port " + port);
    }
}    

Once the ThreadPoolExecutor has been coded, all that remains is to set the Endpoint publisher’s executor property to an instance of the worker class. The details of thread management do not intrude at all into the publisher.

The multithreaded Endpoint publisher is suited for lightweight production, but this publisher is not a service container in the true sense; that is, a software application that readily can deploy many web services at the same port. A web container such as Tomcat, which is the reference implementation, is better suited to publish multiple web services. Tomcat is introduced in later examples.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required