Concepts / Threads and Concurrency Essentials

Threads and Concurrency Essentials

A server that finishes one client before accepting the next, as the DateServer sample does, can be held up by a single slow or idle connection.

  • Programming

A Shop With One Counter

Imagine a small shop with one counter and one clerk. The clerk serves a customer from start to finish before turning to the next person in line. If the first customer is quick, nobody minds. If the first customer settles in and talks for an hour, everyone behind them waits for the entire hour.

A network server that handles connections one at a time has exactly this problem. A single connection that stays open can keep the whole server occupied, and every other client has to wait. This article follows the problem step by step, and then shows how threads let a server keep serving other clients while one connection lingers.

Tracing a Server That Serves One Client at a Time

The DateServer.java sample program from this course is an extremely simple network server. It does not use threads. Because of that, the server has to finish its work with one client before it is able to accept a connection from a different client. The server is not doing two jobs at once. It works through its connections in order.

The exchange with a client might be very brief, and for a simple date service it often is. We still cannot assume every client will behave that way. A client could connect, stay connected for a long time, and keep the server occupied the whole while. In a server with no threads, every client that arrives during that time has to wait. The diagram below traces a client that connects and sends nothing, while a second client tries to connect.

Client Aconnects and stays silentServerone path of executionClient Btrying to connectconnectswaits for datatries to connectno service yet
While the server waits for an idle client to send its data, what happens to a second client that is trying to connect?

Read the diagram in order. Client A has connected, and the server is working with it. The server is waiting on input that never arrives, so it does not move on. Client B's attempt to connect is made, but the server cannot give B service until it is finished with A. Client B has to wait, and nothing about B's own behaviour caused the delay. The single connection that stopped responding is what held up everyone else.

What do you think happens?

In a server that handles one client at a time, if Client A connects and sends nothing, can Client B be served while A stays connected?

  • Yes, because the server accepts every connection immediately

  • No, because the server must finish with A before it moves to B

Reveal answer
Answer:

No, because the server must finish with A before it moves to B

The source says the non-threaded DateServer has to finish its work with one client before it can accept a connection from a different client, so an idle first client holds up every client behind it.

How Separate Threads Let Other Clients Proceed

A threaded server changes the ordering problem. Instead of one path of execution that must finish with each client in turn, the server can use threads so that it deals with several clients at the same time. A thread is an independent path of execution, so while one thread is waiting on one client, another thread can be working with a different client. The server is no longer locked to a single line.

The shape of this arrangement is simple. Several clients send requests to one server, and the server gives each connection its own thread. Each thread carries on with its own client, so the progress of one client does not dictate when another client can be served. The diagram below contrasts the two orders in which the clients are handled.

Client A servedThread for AClient B waitingThread for BClient C waitingThread for Cthenthenruns alongsideruns alongside
How does the order in which clients are served differ between a server that handles one client at a time and one that gives each client its own thread?

The benefit is that other clients keep receiving service when one of them is slow or idle. The source is careful about what this diagram does not claim. It does not say the server is always fast, and it does not say threads are free. It shows only that several conversations can be in progress together, each on its own thread.

Serial and Threaded Servers Compared

It helps to set the two designs next to each other. The non-threaded server in the DateServer example works through its clients in sequence. The threaded server gives separate threads to separate connections. The table summarizes the differences that matter for the problem studied here.

AspectSerial server (DateServer style)Threaded server
Clients handledOne at a time, in orderSeveral at the same time
Effect of an idle clientHolds up every client behind itOnly its own thread is stalled; others continue
Execution pathsOne path that finishes each client in turnA separate thread for each connection
Ability to accept new work while a client lingersNot available until the current client finishesOther threads keep serving other clients

Serial and threaded server designs compared for a lingering connection

Following a Thread Beside a Silent Client

A misbehaving client is one that stays connected without sending the data the server expects. This is not a client that sends bad data. It is a client that sends nothing useful while keeping the connection open. From the server's point of view, its thread is waiting for input that never arrives.

The source says such a client can hang up its own thread indefinitely. The important point is what does not happen: the other threads keep going. The state diagram below models the thread paired with the silent client. The states are a teaching model for following the thread, not a full description of any particular implementation.

Connectedconnection openWaiting for datano input yetServing clientexpected data arrivedwaitsclient stays silentexpected data arrives
When a thread is waiting for data from a connected client that sends nothing, what state is it in, and what moves it out of that state?

Only the silent client's thread is in the waiting state. The thread can remain there for as long as the client stays silent. Meanwhile, the threads paired with other clients are separate paths of execution, so they are not stuck in that waiting state and can keep serving their own clients.

Tracing Three Connections With One Silent Client

Worked example

One Silent Client Among Three

A threaded server has three clients. Client A connects and sends nothing. Client B connects and sends the data the server expects. Client C connects and sends the data the server expects. What happens to each thread?

  1. 1
    Step 1: Client A connects

    The server gives A's connection its own thread. That thread waits on A, which sends nothing useful.

  2. 2
    Step 2: Client B connects

    The server gives B's connection a separate thread, independent of A's thread.

  3. 3
    Step 3: B sends its data

    B's thread receives the expected input and carries on with B. A's waiting does not block this.

  4. 4
    Step 4: Client C connects and sends its data

    C's thread is also separate, so C is served while A's thread is still waiting.

Result

Clients B and C are served. Only A's own thread stays stalled, which is the behaviour the source describes for a misbehaving client in a threaded server.

Mistakes Beginners Make About Threads

  • Common mistake

    Believing that adding threads makes every server faster

    Why it fails

    The source says the diagram does not claim the server is always fast, and it does not say threads are free. Threads are about letting several clients make progress together.

    Do this instead

    Describe threads as a way to keep one lingering connection from blocking others, not as a universal speed-up.

  • Common mistake

    Expecting the simple DateServer to show a clear benefit from threads

    Why it fails

    The source notes DateServer's interaction with each client is short, so the benefit of threads hardly shows for such a simple server.

    Do this instead

    Use DateServer as the starting point for the conversion, and expect the advantage to matter most in servers whose clients can stay connected for a long time.

  • Common mistake

    Thinking a silent client stops the entire server

    Why it fails

    A misbehaving client can hang up its own thread indefinitely, but the other threads can continue with other clients.

    Do this instead

    Trace the stall to the single thread paired with that client, and check that the other threads are still running.

Practicing the Idle Client Trace

EASY

A serial server has three clients queued: A, B, and C. A connects and sends nothing. Explain what happens to B and C while A stays connected. Then explain how the same situation changes if the server gives each connection its own thread.

Hints
  • Ask which client the server is finished with before it moves to the next one.
  • In the threaded version, ask which thread is waiting and which threads are independent of it.

Key Takeaways

  • A server that finishes one client before accepting the next, as the DateServer sample does, can be held up by a single slow or idle connection.
  • A thread is an independent path of execution, so giving each connection its own thread lets the server work with several clients at the same time.
  • A misbehaving client stays connected without sending the data the server expects; it can hang up its own thread indefinitely, but other threads can continue serving other clients.
  • Threads change the server's structure, not the basic idea of a client conversation, and the source says the same techniques apply to more complicated servers.
  • Threads do not make every server faster and are not free; their main value here is that one lingering connection does not stop everyone else.