Java Reference
In-Depth Information
are CPU-bound, then the total task may finish more quickly if you can avoid a lot of
switching between threads. Finally, and most importantly, although threads help make
more efficient use of a computer's limited CPU resources, there is still only a finite
amount of resources to go around. Once you've spawned enough threads to use all the
computer's available idle time, spawning more threads just wastes MIPS and memory
on thread management.
The
Executors
class in
java.util.concurrent
makes it quite easy to set up thread
pools. You simply submit each task as a
Runnable
object to the pool. You get back a
Future
object you can use to check on the progress of the task.
Let's look at an example. Suppose you want to gzip every file in the current directory
using a
java.util.zip.GZIPOutputStream
. This is a filter stream that compresses all
the data it writes.
On the one hand, this is an I/O-heavy operation because all the files have to be read and
written. On the other hand, data compression is a very CPU-intensive operation, so you
don't want too many threads running at once. This is a good opportunity to use a thread
pool. Each client thread will compress files while the main program will determine
which files to compress. In this example, the main program is likely to significantly
outpace the compressing threads because all it has to do is list the files in a directory.
Therefore, it's not out of the question to fill the pool first, then start the threads that
compress the files in the pool. However, to make this example as general as possible,
you'll allow the main program to run in parallel with the zipping threads.
Example 3-13
shows the
GZipRunnable
class. It has a single field that identifies the file
to compress. The
run()
method compresses this file and returns.
Example 3-13. The GZipRunnable class
import
java.io.*
;
import
java.util.zip.*
;
public
class
GZipRunnable
implements
Runnable
{
private
final
File
input
;
public
GZipRunnable
(
File
input
)
{
this
.
input
=
input
;
}
@Override
public
void
run
()
{
// don't compress an already compressed file
if
(!
input
.
getName
().
endsWith
(
".gz"
))
{
File
output
=
new
File
(
input
.
getParent
(),
input
.
getName
()
+
".gz"
);
if
(!
output
.
exists
())
{
// Don't overwrite an existing file
try
(
// with resources; requires Java 7
InputStream
in
=
new
BufferedInputStream
(
new
FileInputStream
(
input
));