Simple Java Thread Management (SJT.Mgmt)
|
Applications without thread management.
Designed for daily trips to the grocery store, the stylish
Pacer was a veritable safety hazard and dropped from production.
|
|
|
Applications with thread management.
Sensible, safe, and functional, with elegance and performance,
the Audi A6 is an incredible everyday car.
|
|
Summary
SJT.Mgmt is a very easy to use library for adding thread management in
Java applications. Thread management allows multi-threading without the cost
of running out of memory and straining the CPU. Parameters include initial,
max size, and workload throttling. The library comes from early
experience with JServ's lack of thread management, and recent posts to the
java developer forums.
Why Audi?
Over the past several years, Audi has consistently produced cars with
simple lines, functional interiors, safety features, incredible road handling,
and impressive performance.
SJT.Mgmt endeavours to replicate those qualities in a Java threading library.
It provides simple lines ( a friendly programming interface), functional
interiors ( easy to read code ), safety features ( prevents running memory
errors and taxing CPU), road handling (versatility within various applications),
and impressive performance ( short lock scopes, improved memory requirements,
less threads moving from wait and ready states)
Background
Multi-threading is often required in an application, but the usual step
in introducing threads into an application is often a bad experience . Spawning
threads without any sort of control will bring your application down, particularly
if its heavily used . The following are procedures in a multi-threading system:
- Every thread in a system fights for execution time.
- Memory is needed for each thread stack.
- The garbage collector (in Java) is another thread fighting for execution
time. Running at minimum priority, it may not free memory associated with
dead threads.
- Execution is halted for all but one thread in critical section of shared
code.
- All dormant threads come to life and fight for possesion of a single
token during the notification process.
- All but one thread are placed back into a dormant state.
Models
Most applications are either CPU intensive, I/O intensive, or Human intensive.
CPU Intensive applications are optimized by using multiple CPU hardware,
with each CPU sharing the work load. I/O intensive applications are often
waiting on slower resources, such as disks or network connections. Human
intensive applications are waiting on even slower manual operation, such
as key strokes, mouse movements, and coffee breaks.
SJT.Mgmt can help in all three types of applications, but is most appropriate
for a I/O intensive system. It is very appropriate for applications using
a SocketServer. However, it will definitely help in CPU and Human intensive
applications because of its simple implementation. It is not optimized
for the CPU intensive model as one work load is assigned to only one working
thread, rather than spread the load across multiple processors. Processor
balancing is slated for an upcoming release.
Why thread management
The primary reason for thread management is scalability and safety. Scalablity
is improved since more requests are serviced with no change in resources.
Safety is enhanced by protecting your application from reaching the maximum
allocated memory.
Fear of the unknown! A system without thread management has an increased
number of unknown variants. But a system with thread management has controlled
and known variants: the number of running threads in a system is know, the
memory required for all thread stack is preset and known, the number of unwillfully
spawned threads is known, the number of calls to notify - at all times during
the running of your application - is known. Using thread management resolves
issues of the unknown.
In most cases, the advantages of thread management out weight the disadvantages.
Advantages:
- The number of threads running in your system is capped at a very
specific number.
- The memory needed for total thread stack size is known and will not
grow.
- A fixed and known number of threads contend for execution time per
CPU.
- Thread objects do not need to be constructed during run time.
- Calls to the inefficient notifyAll() will be limited to a strict number
of threads, opposed to unnecessarily notifying an unlimited number of threads.
NotifyAll() will call all threads waiting on an object lock -- only one
thread obtains the object lock while all other threads return to the wait
state.
- The garbage collector does not need to mark and sweep dead thread
objects, in order to free memory.
Disadvantages:
- Additional object synchronization is required. Objects are placed
onto a collection of some sort, typically a queue, in order to await execution.
The queue itself must be synchronized.
- Working threads may block on a specific task forever, which will reduce
your effective working threads by a significant number, one/pool size. A
maintenance thread is required to check for blocked threads, and assumptions
must be made on expected execution timing.
Performance
In a very simplified and slightly revealing ( yet ultimately inconclusive)
test of a recursive square root equation SJT.Mgmt library was consistently
magnitudes faster than those using a spawning thread model.
Following is the outcome of a test involving one square root calculation
per client, with 1000 distinct client requests.
Spawned Threads: 984 ms
SJT.Mgmt WorkManager Non-blocking: 246 ms
SJT.Mgmt WorkManager Blocking: 268 ms
Environment was as follows:
$uname -a
SunOS sunnyboy 5.8 Generic_108528-14 sun4u sparc SUNW,UltraAX-i2
Which is a Solaris 8, 500 Mhz Sparc, 512 MB Ram
$java -version
java version "1.3.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1_01)
Java HotSpot(TM) Client VM (build 1.3.1_01, mixed mode)
Please conduct your own tests and come to a conclusion based on your application
requirements.
Quick Solutions
Be aware of the -X memory options available with the JVM, which affords
the easiest and most effective performance increase. Effective because allocating
and freeing memory is the slowest operation for the JVM.
-Xms<size> set initial
Java heap size
-Xmx<size> set maximum
Java heap size
-Xss<size>
set java thread stack size
The default heap size is probably not optimal for your application.
The answer is to calculate needed memory requirements and test often. Set
the initial size equal to the max size if the architecture can afford the
memory, and the application can deal with a slower initial start-up.
java -Xms1M -Xms5M MyQuickTest
java -Xms10M -Xmx50M MyStableServer
java -Xms1000M -Xms1000M MyFatEJBServer
The default stack size may be fine for your application, as it is difficult
to determine the optimal size. If you choose to spawn threads, attempt to
slim down the stack size.
java -Xss128K MySpawningServer
In short when using the -X options avoid allocating new heap memory during
run time, and minimize the thread stack size as best possible.
All applications must be tested. With multi-threaded applications the importance
of testing is magnified. Objects can incorrectly access shared objects, threads
can remain dormant forever, tokens may never be released. Testing will determine
your point of failure; it will focus your attention on critical pieces of
faulty code, or prompt you to introduce preventive measures.
Conclusion
Use thread management when you have no control over your clients. If your
application is accepting connections from an unknown number of clients,
you need thread management. If your system is accepting clients over a public
domain then you need thread management. If you expect more than 40
threads per CPU running in your system concurrently, you most likely need
thread management. If your system is pushing its memory and CPU capability
you should introduce thread management.
Carefully test your application and use the simple -X options in all cases.
Read Me:
The following articles have good explanations of the tricky issues in multi-threading.
http://java.sun.com/docs/hotspot/threads/threads.html
http://developer.java.sun.com/developer/TechTips/2000/tt0328.html
http://developer.java.sun.com/developer/technicalArticles//Interviews/Stefanini/index.html
Other:
SJT.Mgmt uses Junit for testing code. Please download this library at
Junit.sourceforge.net
prior to compiling ours.
XML is a system to system language and has no value in configuration files
maintained by humans, hence you don't need ant for building.
Mailing Lists:
There are two mailing lists hosted on sourceforge.net
One public list for general users,
users
One private list for contributors,
devel
Accolades:
Caucho team for their thread management in their Resin Servlet engine,
well in advance of JServ, and making Servlets a viable technology.
www.cauco.com
Matt Welsh for his Nonblocking I/O for Java.
http://www.cs.berkeley.edu/~mdw/proj/java-nbio/
Audi for building the A4 and A6, the S4, and the OffRoad.
www.audi.com
Graciously hosted by: