img
. . .
The right way to do this is to run your method in a separate thread. This way, when you run the
method, the applet thread is idle. You request a repaint, you go to sleep, and now the repaint can
occur in the applet thread!
Socket Server (Master/Slave Version)
The socket server example uses threads to implement a "standard" socket port server. A standard
socket server listens on a socket port and when a message arrives, forks a process to service the
request. The server program first sets up all the needed socket information. The server then enters
a loop, waiting to service a socket port. When a connect request is sent to the socket port, the
server creates a new thread to handle the requests on this socket file descriptor.
The newly created listener thread then receives requests on this socket in the function
producer() until the string "End" comes across. For each request, the listener thread creates a
new thread to handle it. That worker thread processes the request in processRequest(), which
sleeps for a bit (simulating disk I/O) and then sends a reply back across the file descriptor.
The client side of the example (not shown) sends 1000 requests to the server for each file
descriptor you request on the command line (default 1). It waits for each reply and exits when the
server returns "End." This client code can also be run from different machines by multiple users.
The code is a little bit artificial because we wrote it to look as much as possible like our
producer/consumer example. We also added some instrumentation to it, so it will count the
number of threads created and running. One notable artifice is that we accept 1000 requests from
each socket rather than one request from each of 1000 sockets, as you might expect. Our design
gives the program a two-level structure, with the main thread waiting for new socket requests [in
the accept() call]. The main thread creates a new thread to handle each new socket, and that
new thread then waits for the 1000 requests, spawning 1000 additional threads, one per request.
Socket Server (Producer/Consumer Version)
Run the master/slave code on a fast enough machine and you will discover that it creates so many
threads that it runs out of memory! This is not a good thing. One solution is to keep careful track
of how many threads you have created and how many have exited. A better solution would be to
redesign the program to be a producer/consumer model. This way you will be able to control the
number of threads with no problem and you will be able to use the list of outstanding requests as a
buffer for when the number of requests exceeds the ability of the program to handle them.
Of course, if the rate of incoming requests exceeds the ability to reply for too long, you will
eventually have to simply reject the requests. You could have the producer thread send explicit
rejections to the client programs, or it could simply refuse to call accept() until there is room on
the list. In this case, the kernel will queue up a few requests, then simply refuse to acknowledge
any more requests.
Most of the code for the producer/consumer version (Code Example 17-3) is identical to that in
the master/slave version. You will notice that most of the code is stolen directly from Code
Example 6-12 . Both the producer() and consumer() functions are identical. Really, all that
we're doing is redirecting the producer, from creating new threads for each request, to placing
those requests onto a queue and letting the consumers worry about them.
Search WWH :
Custom Search
Previous Page
Multithreaded Programming with JAVA - Topic Index
Next Page
Multithreaded Programming with JAVA - Bookmarks
Home