| [Issue
181] Generating Static Proxy Classes - 2/2
In this newsletter, we show how the Generator described in
our previous issue can be used to create virtual proxy
classes statically, that is, by generating code instead of
using dynamic proxies. |
[Issue
180] Generating Static Proxy Classes - 1/2
In this newsletter, we have a look at how we can create
new classes in memory and then inject them into any
class loader. This will form the basis of a system to
generate virtual proxies statically. |
| [Issue
179] Escape Analysis
Escape analysis can make your code run 110 times faster -
if you are a really really bad programmer to begin with :-)
In this newsletter we look at some of the places where
escape analysis can potentially help us. |
[Issue
178b] WalkingCollection Generics
Generics can be used to further improve the
WalkingCollection, shown in our previous newsletter. |
| [Issue
178] WalkingCollection
We look at how we could internalize the iteration into
a collection by introducing a Processor interface that
is applied to each element. This allows us to manage
concurrency from within the collection. |
[Issue
177] Logging Part 3 of 3
After almost nine years of silence, we come back to bring
the logging series to an end, looking at best practices and
what performance measurements to log. |
| [Issue
176] The Law of the Xerox Copier
Concurrency is easier when we work with immutable objects.
In this newsletter, we define another concurrency law,
The Law of the Xerox Copier, which explains how we can
work with immutable objects by returning copies from
methods that would ordinarily modify the state. |
[Issue
175] Creating Objects Without Calling Constructors
De-Serialization creates objects without calling
constructors. We can use the same mechanism to create
objects at will, without ever calling their constructors. |
| [Issue
174] Java Memory Puzzle Explained
In this newsletter, we reveal the answer to the puzzle from
last month and explain the reasons why the first class
sometimes fails and why the second always succeeds.
Remember this for your next job interview ... |
[Issue
173] Java Memory Puzzle
In this newsletter we show you a puzzle, where a simple
request causes memory to be released, that otherwise could
not. Solution will be shown in the next newsletter. |
| [Issue
172] Wonky Dating
The DateFormat produces some seemingly unpredictable
results parsing the date 2009-01-28-09:11:12 as
"Sun Nov 30 22:07:51 CET 2008". In this newsletter we
examine why and also show how DateFormat reacts to
concurrent access. |
[Issue
171] Throwing ConcurrentModificationException Early
One of the hardest exceptions to get rid of in a system is
th ConcurrentModificationException, which typically occurs
when a thread modifies a collection whilst another is busy
iterating. In this newsletter we show how we can fail on
the modifying, rather than the iterating thread. |
| [Issue
170] Discovering Objects with Non-trivial Finalizers
It is well known that implementing a non-trivial finalize()
method can cause GC and performance issues, plus some
subtle concurrency bugs. In this newsletter, we show how
we can find all objects with a non-trivial finalize()
method, even if they are not currently eligible for
finalization. |
[Issue
169] Monitoring Sockets
In this newsletter, we show two approaches for listening to bytes on sockets.
The first uses the Delegator from our previous newsletter, whereas the second
uses AspectJ to intercept the call to Socket.getInput/OutputStream. We also
write an MBean to publish this information in JConsole. |
| [Issue
168] The Delegator
In this newsletter we show the reflection plumbing needed
for writing a socket monitor that sniffs all the bytes
being sent or received over all the Java sockets. The
Delegator is used to invoke corresponding methods through
some elegant guesswork. |
[Issue
167] Annotation Processing Tool
In this newsletter we answer the question: "How do we force
all subclasses to contain a public no-args constructor?"
The Annotation Processing Tool allows us to check
conditions like this at compile time, rather than only at
runtime. |
| [Issue
166] Serialization Cache
Java's serialization mechanism is optimized for immutable
objects. Writing objects without resetting the stream
causes a memory leak. Writing a changed object twice
results in only the first state being written. However,
resetting the stream also loses the optimization stored in
the stream. |
[Issue
165] Starvation with ReadWriteLocks
In this newsletter we examine what happens when a
ReadWriteLock is swamped with too many reader or writer
threads. If we are not careful, we can cause starvation of
the minority in some versions of Java. |
| [Issue
164] Why 0x61c88647?
Prior to Java 1.4, ThreadLocals caused thread contention,
rendering them useless for performant code. In the new
design, each thread contains its own ThreadLocalMap, thus
improving throughput. However, we still face the possibility
of memory leaks due to values not being cleared out of the
ThreadLocalMap with long running threads. |
[Issue
163] Book Review: Effective Java 2nd Edition
Joshua Bloch has at long last published an updated version
of Effective Java. An essential guide for professional
Java programmers who are interested in producing high
quality code, this book is also very readable. In this
newsletter we describe some of the nuggets found in the
book. |
| [Issue
162] Exceptions in Java
In this article, we look at exception handling in Java. We
start with the history of exceptions, looking back at the
precursor of Java, a language called Oak. We see reasons
why Thread.stop() should not be used and discover the
mystery of the RuntimeException name. We then look at some
best practices that you can use for your coding, followed
by some worst practices, in the form of exception
anti-patterns. |
[Issue
161] Of Hacking Enums and Modifying "final static" Fields
The developers of the Java language tried their best to
stop us from constructing our own enum instances. However,
for testing purposes, it can be useful to temporarily add
new enum instances to the system. In this newsletter we
show how we can do this using the classes in sun.reflect.
In addition, we use a similar technique to modify static
final fields, which we need to do if we want the switch
statements to still work with our new enums. |
| [Issue
160] The Law of the Uneaten Lutefisk
Imagine a very stubborn viking father insisting that his equally
stubborn child eat its lutefisk before going to sleep. In
real life one of the "threads" eventually will give up, but
in Java, the threads become deadlocked, with neither giving
an inch. In this newsletter we discover how we can
sometimes escape from such deadlocked situations in Java
and learn why the stop() function should never ever ever be
called. |
[Issue
159] The Law of Sudden Riches
We all expect faster hardware to make our code execute
faster and better. In this newsletter we examine why this
is not always true. Sometimes the code breaks on faster
servers or executes slower than on worse hardware. |
| [Issue
158] Polymorphism Performance Mysteries Explained
In this newsletter, we reveal some of the polymorphism
mysteries in the JDK. The HotSpot Server Compiler can
distinguish between mono-morphism, bi-morphism and
poly-morphism. The bi-morphism is a special case which
executes faster than poly-morphism. Mono-morphism can be
inlined by the compiler in certain circumstances, thus not
costing anything at all. |
[Issue
157] Polymorphism Performance Mysteries
Late binding is supposed to be a bottleneck in
applications - this was one of the criticisms of
early Java. The HotSpot Compiler is however rather good at
inlining methods that are being called through
polymorphism, provided that we do not have very many
implementation subclasses. |
| [Issue
156] The Law of Cretan Driving
The Law of Cretan Driving looks at what happens when we
keep on breaking the rules. Eventually, we might
experience a lot of pain when we migrate to a new
architecture or Java Virtual Machine. Even if we decide
not to obey them, we need to know what they are. In this
newsletter, we point you to some essential reading for
every Java Specialist. |
[Issue
155] The Law of the Micromanager
In good Dilbert style, we want to avoid having
Pointy-Haired-Bosses (PHBs) in our code. Commonly called
micromanagers, they can make a system work extremely
inefficiently. My prediction is that in the next few years,
as the number of cores increases per CPU, lock contention
is going to be the biggest performance problem facing
companies. |
| [Issue
154] ResubmittingScheduledPoolExecutor
Timers in Java have suffered from the typical Command
Pattern characteristics. Exceptions could stop the timer
altogether and even with the new ScheduledPoolExecutor,
a task that fails is cancelled. In this newsletter we
explore how we could reschedule periodic tasks
automatically. |
[Issue
153] Timeout on Console Input
In this newsletter, we look at how we can read from the
console input stream, timing out if we do not get a
response by some timeout. |
| [Issue
152] The Law of the Corrupt Politician
Corruption has a habit of creeping into system that do not
have adequate controls over their threads. In this law, we
look at how we can detect data races and some ideas to
avoid and fix them. |
[Issue
151] The Law of the Leaked Memo
In this fifth law of concurrency, we look at a deadly law
where a field value is written early. |
| [Issue
150] The Law of the Blind Spot
In this fourth law of concurrency, we look at the problem
with visibility of shared variable updates. Quite often,
"clever" code that tries to avoid locking in order to
remove contention, makes assumptions that may result in
serious errors. |
[Issue
149] The Law of the Overstocked Haberdashery
Learn how to write correct concurrent code by understanding
the Secrets of Concurrency. This is the third part of a
series of laws that help explain how we should be writing
concurrent code in Java. In this section, we look at why
we should avoid creating unnecessary threads, even if they
are not doing anything. |
| [Issue
148] Snappy JSliders in Swing
Recent versions of Swing do a good job of mimicking the
underlying platform, with a few caveats. For example,
the JSlider only snaps onto the correct tick once you let
go of the mouse. Here I present a fix for this problem
with a non-intrusive one-liner that we can add to the
application code. |
[Issue
147] The Law of the Distracted Spearfisherman
Learn how to write correct concurrent code by understanding
the Secrets of Concurrency. This is the second part of a
series of laws that help explain how we should be writing
concurrent code in Java. We look at how to debug a
concurrent program by knowing what every thread in the
system is doing. |
| [Issue
146] The Secrets of Concurrency (Part 1)
Learn how to write correct concurrent code by understanding
the Secrets of Concurrency. This is the first part of a
series of laws that help explain how we should be writing
concurrent code in Java. |
[Issue
145] TristateCheckBox Revisited
The Tristate Checkbox is widely used to
represent an undetermined state of a check box. In this
newsletter, we present a new version of this popular
control, retrofitted to Java 5 and 6. |
| [Issue
144] Book Review: Java Puzzlers
Experienced Java programmers will love the Java Puzzlers
book by Josh Bloch and Neal Gafter, both well known Java
personalities. In this newsletter, we look at two of the
puzzles as a teazer for the book. |
[Issue
143] Maths Tutor in GWT
Google Web Toolkit (GWT) allows ordinary Java Programmers
to produce highly responsive web user interfaces, without
needing to become experts in JavaScript. Here we
demonstrate a little maths game for practicing your
arithmetic. Included is an Easter egg. |
| [Issue
142] Instrumentation Memory Counter
Memory usage of Java objects has been a mystery for many
years. In this newsletter, we use the new instrumentation
API to predict more accurately how much memory an object
uses. Based on earlier newsletters, but revised for Java
5 and 6. |
[Issue
141] Hacking Enums
Enums are implemented as constant flyweights. You cannot
construct them. You cannot clone them. You cannot
make copies with serialization. But here is a way we can
make new ones in Java 5. |
| [Issue
140] Book Review: Java Generics and Collections
Java Generics and Collections is the "companion book" to
The Java Specialists' Newsletter. A well written book that
explains generics really nicely, including some difficult
concepts. In addition, they cover all the new collection
classes up to Java 6 Mustang. |
[Issue
139] Mustang ServiceLoader
Mustang introduced a ServiceLoader than can be used to
load JDBC drivers (amongst others) simply by including a
jar file in your classpath. In this newsletter, we look at
how we can use this mechanism to define and load our own
services. |
| [Issue
138] Better SQLExceptions in Java 6
Java 6 has support for JDBC 4, which, amongst other things,
gives you better feedback of what went wrong with your
database query. In this newsletter we demonstrate how this
can be used. |
[Issue
137] Creating Loggers DRY-ly
A common idiom for logging is to create a logger in each class
that is based on the class name. The name of the class is
then duplicated in the class, both in the class definition and
in the logger field definition, since the class is for some
reason not available from a static context. Read how to solve
that problem. |
| [Issue
136] Sneaking in JDBC Drivers
In this newsletter, we look at a technique of how we can
replace an existing database driver with our own one. This
could be used to migrate an application to a new database
where you only have the compiled classes. Or it could be used
to insert a monitoring JDBC connection that measures the
length of database queries. |
[Issue
135] Are you really Multi-Core?
With Java 5, we can measure CPU cycles per thread. Here is a
small program that runs several CPU intensive tasks in
separate threads and then compares the elapsed time to the
total CPU time of the threads. The factor should give you
some indication of the CPU based acceleration that the multi
cores are giving you. |
| [Issue
134] DRY Performance
As developers we often hear that performance often comes at
the price of good design. However when we have our performance
tuning hats on, we often find that good design is essential to
help achieve good performance. In this article we will explore
one example of where a good design choice has been essential
in an effort to improve performance. |
[Issue
133] Safely and Quickly Converting EJB3 Collections
When we query the database using EJB3, the Query
object returns an untyped collection. In this newsletter we
look at several approaches for safely converting this to a
typed collection. |
| [Issue
132] Thread Dump JSP in Java 5
Sometimes it is useful to have a look at what the threads are
doing in a light weight fashion in order to discover tricky
bugs and bottlenecks. Ideally this should not disturb the
performance of the running system. In addition, it should be
universally usable and cost nothing. Have a look at how we do
it in this newsletter. |
[Issue
131] Sending Emails from Java
In this newsletter, we show how simple it is to send
emails from Java. This should obviously not be used for
sending unsolicited emails, but will nevertheless illustrate
why we are flooded with SPAM. |
| [Issue
130] Deadlock Detection with new Locks
Java level monitor deadlocks used to be hard to find. Then
along came JDK 1.4 and showed them in CTRL+Break. In JDK 1.5,
we saw the addition of the ThreadMXBean, which made it
possible to continually monitor an application for deadlocks.
However, the limitation was that the ThreadMXBean only worked
for synchronized blocks, and not the new java.util.concurrency
mechanisms. In this newsletter, we take a fresh look at the
deadlock detector and show what needs to change to make it
work under JDK 1.6. Also, we have a look at what asynchronous
exceptions are, and how you can post them to another thread. |
[Issue
129] Fast Exceptions in RIFE
One of the tricks that Java allows us to employ is to change
the control flow of the application using exceptions. This
is generally strongly discouraged, since it makes the code
hard to decipher. In addition, exceptions are notoriously bad
at performance. Here is a trick used in RIFE to make this
work faster. |
| [Issue
128] SuDoKu Madness
In this Java Specialists' Newsletter, we look at a
simple Java program that solves SuDoKu puzzles. |
[Issue
127] Casting like a Tiger
Java 5 adds a new way of casting that does not show
compiler warnings or errors. Yet another way to shoot
yourself in the foot? |
| [Issue
126] Proxy equals()
When we make proxies that wrap objects, we have to remember to
write an appropriate equals() method. Instead of comparing on
object level, we need to either compare on interface level or
use a workaround to achieve the comparisons on the object
level, described in this newsletter. |
[Issue
125] Book Review: Java Concurrency in Practice
We review Java Concurrency in Practice by Brian Goetz.
Brian's book is the most
readable on the topic of concurrency in Java, and
deals with this difficult subject with a wonderful hands-on
approach. It is interesting, useful, and relevant to the
problems facing Java developers today. |
| [Issue
124] Copying Arrays Fast
In this newsletter we look at the difference in performance
between cloning and copying an array of bytes. Beware of the
Microbenchmark! We also show how misleading such a test can
be, but explain why the cloning is so much slower for small
arrays. |
[Issue
123] Strategy Pattern with Generics
The Strategy Pattern is elegant in its simplicity. With this
pattern, we should try to convert intrinsic state to
extrinsic, to allow sharing of strategy objects. It gets
tricky when each strategy object needs a different set of
information in order to do its work. In this newsletter, we
look at how we can use Java 5 Generics to pass the correct
subtype of the context into each strategy object. |
| [Issue
122] Copying Files from the Internet
Sometimes you need to download files using HTTP from a machine
that you cannot run a browser on. In this simple Java program
we show you how this is done. We include information of your
progress for those who are impatient, and look at how the
volatile keyword can be used. |
[Issue
121] How Deep is Your Hierarchy?
Someone asked me yesterday what the maximum inheritance depth
is in Java. I guessed a value of 65535, but for practical
purposes, not more than 5. When I asked performance guru
Kirk Pepperdine to estimate, he shot back with 63. In this
newsletter, we look at the limitations in the JVM and examine
some existing classes. |
| [Issue
120] Exceptions From Constructors
What do you do when an object cannot be properly constructed?
In this newsletter, we look at a few options that are used
and discuss what would be best. Based on the experiences of
writing the Sun Certified Programmer for Java 5 exam. |
[Issue
119] Book Review: "Wicked Cool" Java
The book "Wicked Cool Java" contains a myriad of
interesting libraries, both from the JDK and various open source
projects. In this review, we look at two of these, the
java.util.Scanner and javax.sql.WebRowSet classes. |
| [Issue
118] A Simple Database Viewer
A simple database viewer written in Java Swing that
reads the metadata and shows you all the tables and contents
of the tables, written in under 100 lines of Java code,
including comments. |
[Issue
117] Reflectively Calling Inner Class Methods
Sometimes frameworks use reflection to call
methods. Depending how they find the correct method to
call, we may end up with IllegalAccessExceptions. The
naive approach of clazz.getMethod(name) is not correct
when we send instances of non-public classes. |
| [Issue
116] Closing Database Statements
Don't Repeat Yourself. The mantra of the good Java
programmer. But database code often leads to this
antipattern. Here is a neat simple solution from the
Jakarta Commons DbUtils project. |
[Issue
115] Young vs. Old Generation GC
A few weeks ago, I tried to demonstrate the effects of old vs. new
generation GC. The results surprised me and reemphasized how important GC
is to your overall program performance. |
| [Issue
114] Compile-time String Constant Quiz
When we change libraries, we need to do a full recompile of our code, in
case any constants were inlined by the compiler. Find out which constants
are inlined in this latest newsletter. |
[Issue
113] Enum Inversion Problem
A problem that I encountered when I first started using enums was how
to serialize them to some persistent store. My initial approach was to
write the ordinal to the database. In this newsletter, I explore some
ideas of a more robust approach. It will also show you some applications
of Java generics. |
| [Issue
112] Book Review: Head First Design Patterns
This book is a fantastic introduction to Design Patterns, probably
the best available. In this newsletter, I look at some of the winning
formulae used in the book, and explain why they work. I also give some
tips of where I disagree with the book and some additional information
that will be useful to you. |
[Issue
111] What is faster - LinkedList of ArrayList?
|
| [Issue
110] Break to Labeled Statement
|
[Issue
109] Strategy Pattern of HashCode Equality
|
| [Issue
108] Object Adapter based on Dynamic Proxy
|
[Issue
107] Making Enumerations Iterable
|
| [Issue
106] Multi-line cells in JTable in JDK 1.4+
|
[Issue
105] Performance Surprises in Tiger
|
| [Issue
104] EDT Lockup Detection
|
[Issue
103] New for/in loop gymnastics
|
| [Issue
102] Mangling Integers
|
[Issue
101b] Causing Deadlocks in Swing Code (Follow-up)
|
| [Issue
101] Causing Deadlocks in Swing Code
|
[Issue
100] Java Programmers aren't Born
|
| [Issue
099] Orientating Components Right to Left
|
[Issue
098] References
|
| [Issue
097] Mapping Objects to XML Files using Java 5 Annotations
|
[Issue
096] Java 5 - "final" is not final anymore
|
| [Issue
095b] Follow-up: Self-reloading XML Property Files
|
[Issue
095] Self-reloading XML Property Files
|
| [Issue
094] Java Field Initialisation
|
[Issue
093] Automatically Detecting Thread Deadlocks
|
| [Issue
092] OutOfMemoryError Warning System
|
[Issue
091] Controlling Machines Remotely with Java
|
| [Issue
090] Autoboxing Yourself in JDK 1.5
|
[Issue
089] Catching Uncaught Exceptions in JDK 1.5
|
| [Issue
088] Resetting ObjectOutputStream
|
[Issue
087] sun.reflect.Reflection
|
| [Issue
086b] Initialising Fields before Superconstructor call (Follow-up)
|
[Issue
086] Initialising Fields before Superconstructor call
|
| [Issue
085] Book Review: Pragmatic Programmer
|
[Issue
084] Ego Tripping with Webservices
|
| [Issue
083] End of Year Puzzle
|
[Issue
083b] End of Year Puzzle Follow-up
|
| [Issue
082] TristateCheckBox based on the Swing JCheckBox
|
[Issue
081] Catching Exceptions in GUI Code
|
| [Issue
080] Many Public Classes in One File
|
[Issue
079] Generic toString()
|
| [Issue
078] MemoryCounter for Java 1.4
|
[Issue
077] "Wonderfully disgusting hack"
|
| [Issue
076] Asserting Locks
|
[Issue
075] An Automatic Wait Cursor: WaitCursorEventQueue
|
| [Issue
074] GoF Factory Method in writing GUIs
|
[Issue
073] LinkedHashMap is Actually Quite Useful
|
| [Issue
072] Java and Dilbert
|
[Issue
071] Overloading considered Harmful
|
| [Issue
070b] Multi-Dimensional Arrays - Creation Performance
|
[Issue
070] Too many dimensions are bad for you
|
| [Issue
069b] Results of last survey
|
[Issue
069] Treating Types Equally - or - Life's Not Fair!
|
| [Issue
068] Appending Strings
|
[Issue
067] BASIC Java
|
| [Issue
066] Book Review: Java Performance Tuning by Jack Shirazi
|
[Issue
065] Wait, Cursor, Wait!
|
| [Issue
064] Disassembling Java Classes
|
[Issue
063] Revisiting Stack Trace Decoding
|
| [Issue
062b] Follow-up and Happy New Year!
|
[Issue
062] The link to the outer class
|
| [Issue
061] Double-checked locking
|
[Issue
060] Nulling variables and garbage collection
|
| [Issue
059b] Follow-up to Loooong Strings
|
[Issue
059] When arguments get out of hand...
|
| [Issue
058] Counting bytes on Sockets
|
[Issue
057] A Tribute to my Dad, Hans Rudolf Kabutz
|
| [Issue
056] Shutting down threads cleanly
|
[Issue
055] Once upon an Oak ...
|
| [Issue
054b] Follow-up to JDK 1.4 HashMap hashCode() mystery
|
[Issue
054] HashMap requires a better hashCode() - JDK 1.4 Part II
|
| [Issue
053] Charting unknown waters in JDK 1.4 Part I
|
[Issue
052] J2EE Singleton
|
| [Issue
051] Java Import Statement Cleanup
|
[Issue
050] Commenting out your code?
|
| [Issue
049] Doclet for finding missing comments
|
[Issue
048] Review: The Secrets of Consulting
|
| [Issue
047] Lack of Streaming leads to Screaming
|
[Issue
046] "The compiler team is writing useless code again ..."
|
| [Issue
045] Multi-line cells in the JTable
|
[Issue
044] Review: Object-Oriented Implementation of Numerical Methods
|
| [Issue
043] Arrgh, someone wants to kill me!
|
[Issue
042] Speed-kings of inverting booleans
|
| [Issue
041] Placing components on each other
|
[Issue
040] Visiting your Collection's Elements
|
| [Issue
039] Why I don't read your code comments ...
|
[Issue
038a] Counting Objects Clandestinely
|
| [Issue
038b] Counting Objects Clandestinely - Follow-up
|
[Issue
037] Checking that your classpath is valid
|
| [Issue
036] Using Unicode Variable Names
|
[Issue
035] Doclets Find Bad Code
|
| [Issue
034] Generic Types with Dynamic Decorators
|
[Issue
033] Making Exceptions Unchecked
|
| [Issue
032] Exceptional Constructors - Resurrecting the dead
|
[Issue
031] Hash, hash, away it goes!
|
| [Issue
030] What do you Prefer?
|
[Issue
029] Determining Memory Usage in Java
|
| [Issue
028] Multicasting in Java
|
[Issue
027] Circular Array List
|
| [Issue
026] Package Versioning
|
[Issue
025] Final Newsletter
|
| [Issue
024] Self-tuning FIFO Queues
|
[Issue
023] Socket Wheel to handle many clients
|
| [Issue
022] Classloaders Revisited: "Hotdeploy"
|
[Issue
021] Non-virtual Methods in Java
|
| [Issue
020] Serializing Objects Into Database
|
[Issue
019] Finding Lost Frames
|
| [Issue
018] Class names don't identify a class
|
[Issue
017b] Follow-up
|
| [Issue
017a] Switching on Object Handles
|
[Issue
016] Blocking Queue
|
| [Issue
015] Implementing a SoftReference based HashMap
|
[Issue
014] Insane Strings
|
| [Issue
013b] Follow-up
|
[Issue
013a] Serializing GUI Components Across Network
|
| [Issue
012] Setting focus to second component of modal dialog
|
[Issue
011] Hooking into the shutdown call
|
| [Issue
010] Writing GUI Layout Managers
|
[Issue
009] Depth-first Polymorphism
|
| [Issue
008] boolean comparisons
|
[Issue
007] java.awt.EventQueue
|
| [Issue
006] Implementation code inside interfaces
|
[Issue
005] Dynamic Proxies - Short Tutorial
|
| [Issue
004] Logging part 2
|
[Issue
003] Logging part 1
|
| [Issue
002] Anonymous Inner Classes
|
[Issue
001] Deadlocks
|