This chapter is from the book

This chapter is from the book

Objects provide a way to divide a program into independent sections. Often,
you also need to turn a program into separate, independently running subtasks.

Each of these independent subtasks is called a thread, and
you program as if each thread runs by itself and has the CPU to itself.
Some underlying mechanism is actually dividing up the CPU time for you, but in
general, you don't have to think about it, which makes programming with
multiple threads a much easier task.

A process is a self-contained running program with its own address
space. A multitasking operating system is capable of running more than
one process (program) at a time, while making it look like each one is chugging
along on its own, by periodically switching the CPU from one task to another. A
thread is a single sequential flow of control within a process. A
single process can thus have multiple concurrently executing threads.

There are many possible uses for multithreading, but in general,
you'll have some part of your program tied to a particular event
or resource, and you don't want that to hold up the rest of your program.
So, you create a thread associated with that event or resource
and let it run independently of the main program.

Concurrent programming is like stepping into an entirely new world and
learning a new programming language, or at least a new set of language concepts.
With the appearance of thread support in most microcomputer operating
systems, extensions for threads have also been appearing in programming
languages or libraries. In all cases, thread programming:

Seems mysterious and requires a shift in the way you think about
programming

Looks similar to thread support in other languages, so when you
understand threads, you understand a common tongue

And although support for threads can make Java a more complicated
language, this isn't entirely the fault of Javathreads are
tricky.

Understanding concurrent programming is on the same order of difficulty as
understanding polymorphism. If you apply some effort, you can fathom the basic
mechanism, but it generally takes deep study and understanding in order to
develop a true grasp of the subject. The goal of this chapter is to
give you a solid foundation in the basics of concurrency so that you can
understand the concepts and write reasonable multithreaded programs. Be
aware that you can easily become overconfident, so if you are writing anything
complex, you will need to study dedicated books on the topic.

Motivation

One of the most compelling reasons for concurrency is to produce a responsive
user interface. Consider a program that performs some CPU-intensive operation
and thus ends up ignoring user input and being unresponsive. The basic problem
is that the program needs to continue performing its operations, and at the same
time it needs to return control to the user interface so that the program can
respond to the user. If you have a "quit" button, you don't want
to be forced to poll it in every piece of code you write in your program, and
yet you want the quit button to be responsive, as if you were checking it
regularly.

A conventional method cannot continue performing its operations and at the
same time return control to the rest of the program. In fact, this sounds like
an impossible thing to accomplish, as if the CPU must be in two places at once,
but this is precisely the illusion that concurrency provides.

Concurrency can also be used to optimize throughput. For example, you might
be able to do important work while you're stuck waiting for input to arrive
on an I/O port. Without threading, the only reasonable solution is to
poll the I/O port, which is awkward and can be difficult.

If you have a multiprocessor machine, multiple threads may be
distributed across multiple processors, which can dramatically improve
throughput. This is often the case with powerful multiprocessor web servers,
which can distribute large numbers of user requests across CPUs in a program
that allocates one thread per request.

One thing to keep in mind is that a program with many threads must
be able to run on a single-CPU machine. Therefore, it must also be possible to
write the same program without using any threads. However,
multithreading provides a very important organizational benefit, so
that the design of your program can be greatly simplified. Some types of
problems, such as simulationa video game, for exampleare very
difficult to solve without support for concurrency.

The threading model is a programming convenience to simplify
juggling several operations at the same time within a single program. With
threads, the CPU will pop around and give each thread some of
its time. Each thread has the consciousness of constantly having the
CPU to itself, but the CPU's time is actually sliced between all the
threads. The exception to this is if your program is running on
multiple CPUs, but one of the great things about threading is that you
are abstracted away from this layer, so your code does not need to know whether
it is actually running on a single CPU or many. Thus, threads are a way
to create transparently scalable programsif a program is running too
slowly, it can easily be made faster by adding CPUs to your computer.
Multitasking and multithreading tend to be the most reasonable ways to
utilize multiprocessor systems.

Threading can reduce computing efficiency somewhat in single-CPU
machines, but the net improvement in program design, resource balancing, and
user convenience is often quite valuable. In general, threads enable
you to create a more loosely-coupled design; otherwise, parts of your code would
be forced to pay explicit attention to tasks that would normally be handled by
threads.