lecture 15: simple java web server

90
COMP 150-CCP COMP 150-CCP Concurrent Programming Concurrent Programming Lecture 15: Simple Java Web Server Dr. Richard S. Hall [email protected] Concurrent programming – March 11, 2008

Upload: others

Post on 04-Feb-2022

4 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Lecture 15: Simple Java Web Server

COMP 150-CCPCOMP 150-CCPConcurrent ProgrammingConcurrent Programming

Lecture 15:Simple Java Web Server

Dr. Richard S. Hall [email protected]

Concurrent programming – March 11, 2008

Page 2: Lecture 15: Simple Java Web Server

Web Server FeaturesWeb Server Features

● Targets Java Foundation profile i.e., doesn't use advanced Java features so it should be

usable on small devices

● File-based i.e., it does not support dynamic content, such as CGI

scripts, servlets, or JSPs Also supports directory content

▴ If possible, it will convert a directory request to “index.html”

● Configurable● Multi-threaded

Page 3: Lecture 15: Simple Java Web Server

Web Server General AlgorithmWeb Server General Algorithm

Step 1 – Listen for requests until told to stop

Step 2 – Upon connection receiptStep 2.1 – Parse requestStep 2.2 – Create and send response

Step 3 – Go to step 1

Page 4: Lecture 15: Simple Java Web Server

Web Server StartupWeb Server Startup

● Code for HttpServer.start():

public synchronized void start() throws IOException { if (m_state == INACTIVE_STATE) { m_serverSocket = new ServerSocket(m_port); m_serverThread = new Thread(new Runnable() { public void run() { acceptConnections(); } }, "HttpServer"); m_state = ACTIVE_STATE; m_serverThread.start(); } else if (m_state == STOPPING_STATE) { throw new IllegalStateException( "Server is in process of stopping."); }}

Page 5: Lecture 15: Simple Java Web Server

Web Server StartupWeb Server Startup

● What happens when start() is called?

public synchronized void start() throws IOException { if (m_state == INACTIVE_STATE) { m_serverSocket = new ServerSocket(m_port); m_serverThread = new Thread(new Runnable() { public void run() { acceptConnections(); } }, "HttpServer"); m_state = ACTIVE_STATE; m_serverThread.start(); } else if (m_state == STOPPING_STATE) { throw new IllegalStateException( "Server is in process of stopping."); }}

Page 6: Lecture 15: Simple Java Web Server

Web Server StartupWeb Server Startup

● What happens when start() is called?

public synchronized void start() throws IOException { if (m_state == INACTIVE_STATE) { m_serverSocket = new ServerSocket(m_port); m_serverThread = new Thread(new Runnable() { public void run() { acceptConnections(); } }, "HttpServer"); m_state = ACTIVE_STATE; m_serverThread.start(); } else if (m_state == STOPPING_STATE) { throw new IllegalStateException( "Server is in process of stopping."); }}

First call will actually start the server listening

for connections.

Page 7: Lecture 15: Simple Java Web Server

Web Server StartupWeb Server Startup

● What happens when start() is called?

public synchronized void start() throws IOException { if (m_state == INACTIVE_STATE) { m_serverSocket = new ServerSocket(m_port); m_serverThread = new Thread(new Runnable() { public void run() { acceptConnections(); } }, "HttpServer"); m_state = ACTIVE_STATE; m_serverThread.start(); } else if (m_state == STOPPING_STATE) { throw new IllegalStateException( "Server is in process of stopping."); }}

If server is in the process of shutting down, an ex-

ception is thrown.

Page 8: Lecture 15: Simple Java Web Server

Web Server StartupWeb Server Startup

● What happens when start() is called?

public synchronized void start() throws IOException { if (m_state == INACTIVE_STATE) { m_serverSocket = new ServerSocket(m_port); m_serverThread = new Thread(new Runnable() { public void run() { acceptConnections(); } }, "HttpServer"); m_state = ACTIVE_STATE; m_serverThread.start(); } else if (m_state == STOPPING_STATE) { throw new IllegalStateException( "Server is in process of stopping."); }}

If the server is already active, then subsequent calls to start() are

ignored.

Page 9: Lecture 15: Simple Java Web Server

Web Server StartupWeb Server Startup

● Are you prevented from running multiple servers at the same time?public synchronized void start() throws IOException { if (m_state == INACTIVE_STATE) { m_serverSocket = new ServerSocket(m_port); m_serverThread = new Thread(new Runnable() { public void run() { acceptConnections(); } }, "HttpServer"); m_state = ACTIVE_STATE; m_serverThread.start(); } else if (m_state == STOPPING_STATE) { throw new IllegalStateException( "Server is in process of stopping."); }}

Page 10: Lecture 15: Simple Java Web Server

Web Server StartupWeb Server Startup

● Are you prevented from running multiple servers at the same time?public synchronized void start() throws IOException { if (m_state == INACTIVE_STATE) { m_serverSocket = new ServerSocket(m_port); m_serverThread = new Thread(new Runnable() { public void run() { acceptConnections(); } }, "HttpServer"); m_state = ACTIVE_STATE; m_serverThread.start(); } else if (m_state == STOPPING_STATE) { throw new IllegalStateException( "Server is in process of stopping."); }}

No. You can create as many server instances as you want, they just need different port numbers.

Page 11: Lecture 15: Simple Java Web Server

Web Server Request ProcessingWeb Server Request Processing

● HttpServer server thread executes the acceptConnections() method:

private void acceptConnections() { m_threadPool.start(); Socket socket; while (m_serverSocket.isBound() && !m_serverSocket.isClosed()) { try { socket = m_serverSocket.accept(); try { Connection connection = new Connection( this, socket, m_connectionTimeout, m_connectionRequestLimit); m_threadPool.addConnection(connection); } catch (IOException ex) { /* Log */ } } catch (IOException ex) { /* Log */ } } shutdown();}

Page 12: Lecture 15: Simple Java Web Server

Web Server Request ProcessingWeb Server Request Processing

● Does the server thread process incoming connections?

private void acceptConnections() { m_threadPool.start(); Socket socket; while (m_serverSocket.isBound() && !m_serverSocket.isClosed()) { try { socket = m_serverSocket.accept(); try { Connection connection = new Connection( this, socket, m_connectionTimeout, m_connectionRequestLimit); m_threadPool.addConnection(connection); } catch (IOException ex) { /* Log */ } } catch (IOException ex) { /* Log */ } } shutdown();}

Page 13: Lecture 15: Simple Java Web Server

Web Server Request ProcessingWeb Server Request Processing

● Does the server thread process incoming connections?

private void acceptConnections() { m_threadPool.start(); Socket socket; while (m_serverSocket.isBound() && !m_serverSocket.isClosed()) { try { socket = m_serverSocket.accept(); try { Connection connection = new Connection( this, socket, m_connectionTimeout, m_connectionRequestLimit); m_threadPool.addConnection(connection); } catch (IOException ex) { /* Log */ } } catch (IOException ex) { /* Log */ } } shutdown();}

No, they are handed over to a thread pool. Why?

Page 14: Lecture 15: Simple Java Web Server

Web Server Request ProcessingWeb Server Request Processing

● Does the server thread process incoming connections?

private void acceptConnections() { m_threadPool.start(); Socket socket; while (m_serverSocket.isBound() && !m_serverSocket.isClosed()) { try { socket = m_serverSocket.accept(); try { Connection connection = new Connection( this, socket, m_connectionTimeout, m_connectionRequestLimit); m_threadPool.addConnection(connection); } catch (IOException ex) { /* Log */ } } catch (IOException ex) { /* Log */ } } shutdown();}

So the server can handle multiple connections at

the same time.

Page 15: Lecture 15: Simple Java Web Server

Web Server Request ProcessingWeb Server Request Processing

● Why is this method not synchronized?

private void acceptConnections() { m_threadPool.start(); Socket socket; while (m_serverSocket.isBound() && !m_serverSocket.isClosed()) { try { socket = m_serverSocket.accept(); try { Connection connection = new Connection( this, socket, m_connectionTimeout, m_connectionRequestLimit); m_threadPool.addConnection(connection); } catch (IOException ex) { /* Log */ } } catch (IOException ex) { /* Log */ } } shutdown();}

Page 16: Lecture 15: Simple Java Web Server

Web Server Request ProcessingWeb Server Request Processing

● Why is this method not synchronized?

private void acceptConnections() { m_threadPool.start(); Socket socket; while (m_serverSocket.isBound() && !m_serverSocket.isClosed()) { try { socket = m_serverSocket.accept(); try { Connection connection = new Connection( this, socket, m_connectionTimeout, m_connectionRequestLimit); m_threadPool.addConnection(connection); } catch (IOException ex) { /* Log */ } } catch (IOException ex) { /* Log */ } } shutdown();}

It is only ever called by the server thread; thus,

there is no possibility of interference.

Page 17: Lecture 15: Simple Java Web Server

Thread PoolThread Pool

● What is a thread pool ?

Page 18: Lecture 15: Simple Java Web Server

Thread PoolThread Pool

● What is a thread pool ? It is a way of managing a set of threads so that you

can reuse them, instead of creating new ones all the time

Page 19: Lecture 15: Simple Java Web Server

Thread PoolThread Pool

● What is a thread pool ? It is a way of managing a set of threads so that you

can reuse them, instead of creating new ones all the time

▴ Why?

Page 20: Lecture 15: Simple Java Web Server

Thread PoolThread Pool

● What is a thread pool ? It is a way of managing a set of threads so that you

can reuse them, instead of creating new ones all the time

▴ More efficient

Page 21: Lecture 15: Simple Java Web Server

Thread PoolThread Pool

● What is a thread pool ? It is a way of managing a set of threads so that you

can reuse them, instead of creating new ones all the time

▴ More efficient

Typically, a thread executes its run() method and dies when run() returns

▴ We want to avoid this

Instead, we make the thread wait so that we can assign it more work

Page 22: Lecture 15: Simple Java Web Server

Thread PoolThread Pool

● What is a thread pool ? It is a way of managing a set of threads so that you

can reuse them, instead of creating new ones all the time

▴ More efficient

Typically, a thread executes its run() method and dies when run() returns

▴ We want to avoid this

Instead, we make the thread wait so that we can assign it more work

▴ How?

Page 23: Lecture 15: Simple Java Web Server

Thread PoolThread Pool

● What is a thread pool ? It is a way of managing a set of threads so that you

can reuse them, instead of creating new ones all the time

▴ More efficient

Typically, a thread executes its run() method and dies when run() returns

▴ We want to avoid this

Instead, we make the thread wait so that we can assign it more work

▴ We use some shared object on which the thread can wait() and some sort of shared data structure for communicating (e.g., a queue)

Insert new work and notify() the waiting thread about it

Page 24: Lecture 15: Simple Java Web Server

Thread Pool StartupThread Pool Startup

● ThreadPool.start() works similarly to HttpServer.start(), but does even less

public synchronized void start() { if (m_state != STOPPING_STATE) { m_state = ACTIVE_STATE; } else { throw new IllegalStateException( "Thread pool is in process of stopping."); }}

Page 25: Lecture 15: Simple Java Web Server

Thread Pool StartupThread Pool Startup

● ThreadPool.start() works similarly to HttpServer.start(), but does even less

public synchronized void start() { if (m_state != STOPPING_STATE) { m_state = ACTIVE_STATE; } else { throw new IllegalStateException( "Thread pool is in process of stopping."); }} All calls simply set the

state to active, unless...

Page 26: Lecture 15: Simple Java Web Server

Thread Pool StartupThread Pool Startup

● ThreadPool.start() works similarly to HttpServer.start(), but does even less

public synchronized void start() { if (m_state != STOPPING_STATE) { m_state = ACTIVE_STATE; } else { throw new IllegalStateException( "Thread pool is in process of stopping."); }}

Unless the thread pool is in the process of shutting down, then it throws an

exception.

Page 27: Lecture 15: Simple Java Web Server

Thread Pool StartupThread Pool Startup

● Why doesn't it create any threads?

public synchronized void start() { if (m_state != STOPPING_STATE) { m_state = ACTIVE_STATE; } else { throw new IllegalStateException( "Thread pool is in process of stopping."); }}

Page 28: Lecture 15: Simple Java Web Server

Thread Pool StartupThread Pool Startup

● Why doesn't it create any threads?

public synchronized void start() { if (m_state != STOPPING_STATE) { m_state = ACTIVE_STATE; } else { throw new IllegalStateException( "Thread pool is in process of stopping."); }}

Better to defer thread creation until they are needed; doesn't con-

sume resources or slow down startup.

Page 29: Lecture 15: Simple Java Web Server

Thread Pool Connection HandlingThread Pool Connection Handling

● addConnection() is how the server thread communicates with thread pool threads

public synchronized void addConnection(Connection connection) { if (m_state == ACTIVE_STATE) { m_connectionList.add(connection); notify(); if ((m_threadAvailable < m_connectionList.size()) && (m_threadCount < m_threadLimit)) { m_threadCount++; if (m_threadName == Integer.MAX_VALUE) { m_threadName = 1; } else { m_threadName++; } new Thread(m_group, new Runnable() { public void run() { processConnections(); } }, Integer.toString(m_threadName)).start(); } } else { throw new IllegalStateException(...) }}

Page 30: Lecture 15: Simple Java Web Server

Thread Pool Connection HandlingThread Pool Connection Handling

● When are threads created?

public synchronized void addConnection(Connection connection) { if (m_state == ACTIVE_STATE) { m_connectionList.add(connection); notify(); if ((m_threadAvailable < m_connectionList.size()) && (m_threadCount < m_threadLimit)) { m_threadCount++; if (m_threadName == Integer.MAX_VALUE) { m_threadName = 1; } else { m_threadName++; } new Thread(m_group, new Runnable() { public void run() { processConnections(); } }, Integer.toString(m_threadName)).start(); } } else { throw new IllegalStateException(...) }}

Page 31: Lecture 15: Simple Java Web Server

Thread Pool Connection HandlingThread Pool Connection Handling

● When are threads created?

public synchronized void addConnection(Connection connection) { if (m_state == ACTIVE_STATE) { m_connectionList.add(connection); notify(); if ((m_threadAvailable < m_connectionList.size()) && (m_threadCount < m_threadLimit)) { m_threadCount++; if (m_threadName == Integer.MAX_VALUE) { m_threadName = 1; } else { m_threadName++; } new Thread(m_group, new Runnable() { public void run() { processConnections(); } }, Integer.toString(m_threadName)).start(); } } else { throw new IllegalStateException(...) }}

When there are not enough idle threads to

service outstanding connections and the

thread limit hasn't been reached.

Page 32: Lecture 15: Simple Java Web Server

Thread Pool Connection HandlingThread Pool Connection Handling

● Why do we limit the number of threads created?

public synchronized void addConnection(Connection connection) { if (m_state == ACTIVE_STATE) { m_connectionList.add(connection); notify(); if ((m_threadAvailable < m_connectionList.size()) && (m_threadCount < m_threadLimit)) { m_threadCount++; if (m_threadName == Integer.MAX_VALUE) { m_threadName = 1; } else { m_threadName++; } new Thread(m_group, new Runnable() { public void run() { processConnections(); } }, Integer.toString(m_threadName)).start(); } } else { throw new IllegalStateException(...) }}

Page 33: Lecture 15: Simple Java Web Server

Thread Pool Connection HandlingThread Pool Connection Handling

● Why do we limit the number of threads created?

public synchronized void addConnection(Connection connection) { if (m_state == ACTIVE_STATE) { m_connectionList.add(connection); notify(); if ((m_threadAvailable < m_connectionList.size()) && (m_threadCount < m_threadLimit)) { m_threadCount++; if (m_threadName == Integer.MAX_VALUE) { m_threadName = 1; } else { m_threadName++; } new Thread(m_group, new Runnable() { public void run() { processConnections(); } }, Integer.toString(m_threadName)).start(); } } else { throw new IllegalStateException(...) }}

For efficiency and to prevent the server

from being overload-ed with threads.

Page 34: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● ThreadPool.processConnections() is executed by all thread pool threads

// This is pseudo code for presentation purposes

private void processConnections() { Connection connection; while (true) { synchronized (this) { m_threadAvailable++; connection = waitForConnection(); m_threadAvailable--; if (shouldThreadDie(connection)) return; } try { connection.process(); } catch (SocketTimeoutException ex) { /* Log */ } } catch (IOException ex) { /* Log */ } }}

Page 35: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● If all thread pool threads execute this code, won't one thread's connection overwrite another?

// This is pseudo code for presentation purposes

private void processConnections() { Connection connection; while (true) { synchronized (this) { m_threadAvailable++; connection = waitForConnection(); m_threadAvailable--; if (shouldThreadDie(connection)) return; } try { connection.process(); } catch (SocketTimeoutException ex) { /* Log */ } } catch (IOException ex) { /* Log */ } }}

Page 36: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● If all thread pool threads execute this code, won't one thread's connection overwrite another?

// This is pseudo code for presentation purposes

private void processConnections() { Connection connection; while (true) { synchronized (this) { m_threadAvailable++; connection = waitForConnection(); m_threadAvailable--; if (shouldThreadDie(connection)) return; } try { connection.process(); } catch (SocketTimeoutException ex) { /* Log */ } } catch (IOException ex) { /* Log */ } }}

No, each thread will gets its own local

variable copies on its own stack.

Page 37: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● How do thread pool threads communicated with each other and/or coordinate?

// This is pseudo code for presentation purposes

private void processConnections() { Connection connection; while (true) { synchronized (this) { m_threadAvailable++; connection = waitForConnection(); m_threadAvailable--; if (shouldThreadDie(connection)) return; } try { connection.process(); } catch (SocketTimeoutException ex) { /* Log */ } } catch (IOException ex) { /* Log */ } }}

Page 38: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● How do thread pool threads communicated with each other and/or coordinate?

// This is pseudo code for presentation purposes

private void processConnections() { Connection connection; while (true) { synchronized (this) { m_threadAvailable++; connection = waitForConnection(); m_threadAvailable--; if (shouldThreadDie(connection)) return; } try { connection.process(); } catch (SocketTimeoutException ex) { /* Log */ } } catch (IOException ex) { /* Log */ } }}

They coordinate us-ing the thread pool's data structure and synchronize on the thread pool itself.

Page 39: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● What happens in the waitForConnection() pseudo code?

// This is pseudo code for presentation purposes

private void processConnections() { Connection connection; while (true) { synchronized (this) { m_threadAvailable++; connection = waitForConnection(); m_threadAvailable--; if (shouldThreadDie(connection)) return; } try { connection.process(); } catch (SocketTimeoutException ex) { /* Log */ } } catch (IOException ex) { /* Log */ } }}

Page 40: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● This is where threads wait for the arrival of a new connection to processtry { long start = System.currentTimeMillis(); long current = start; while ((m_connectionList.size() == 0) && ((m_threadTimeout == 0) || ((current - start) < m_threadTimeout))) { wait(m_threadTimeout - (current - start)); current = System.currentTimeMillis(); }} catch (InterruptedException ex) { Thread.currentThread().interrupt();}if (m_connectionList.size() == 0) { connection = null;} else { connection = (Connection) m_connectionList.remove(0);}

Page 41: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● What is all of the timing code doing?

try { long start = System.currentTimeMillis(); long current = start; while ((m_connectionList.size() == 0) && ((m_threadTimeout == 0) || ((current - start) < m_threadTimeout))) { wait(m_threadTimeout - (current - start)); current = System.currentTimeMillis(); }} catch (InterruptedException ex) { Thread.currentThread().interrupt();}if (m_connectionList.size() == 0) { connection = null;} else { connection = (Connection) m_connectionList.remove(0);}

Page 42: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● What is all of the timing code doing?

try { long start = System.currentTimeMillis(); long current = start; while ((m_connectionList.size() == 0) && ((m_threadTimeout == 0) || ((current - start) < m_threadTimeout))) { wait(m_threadTimeout - (current - start)); current = System.currentTimeMillis(); }} catch (InterruptedException ex) { Thread.currentThread().interrupt();}if (m_connectionList.size() == 0) { connection = null;} else { connection = (Connection) m_connectionList.remove(0);}

Verifies that the thread at least waits for the thread time-out to expire, unless there is no timeout...

Page 43: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● What is all of the timing code doing?

try { long start = System.currentTimeMillis(); long current = start; while ((m_connectionList.size() == 0) && ((m_threadTimeout == 0) || ((current - start) < m_threadTimeout))) { wait(m_threadTimeout - (current - start)); current = System.currentTimeMillis(); }} catch (InterruptedException ex) { Thread.currentThread().interrupt();}if (m_connectionList.size() == 0) { connection = null;} else { connection = (Connection) m_connectionList.remove(0);}

...probably not strictly necessary.

Page 44: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● Why have threads timeout at all?

try { long start = System.currentTimeMillis(); long current = start; while ((m_connectionList.size() == 0) && ((m_threadTimeout == 0) || ((current - start) < m_threadTimeout))) { wait(m_threadTimeout - (current - start)); current = System.currentTimeMillis(); }} catch (InterruptedException ex) { Thread.currentThread().interrupt();}if (m_connectionList.size() == 0) { connection = null;} else { connection = (Connection) m_connectionList.remove(0);}

Page 45: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● Why have threads timeout at all?

try { long start = System.currentTimeMillis(); long current = start; while ((m_connectionList.size() == 0) && ((m_threadTimeout == 0) || ((current - start) < m_threadTimeout))) { wait(m_threadTimeout - (current - start)); current = System.currentTimeMillis(); }} catch (InterruptedException ex) { Thread.currentThread().interrupt();}if (m_connectionList.size() == 0) { connection = null;} else { connection = (Connection) m_connectionList.remove(0);}

Just another way to conserve resources,

by freeing them when they are no longer needed.

Page 46: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● What happens if the thread is interrupted?

try { long start = System.currentTimeMillis(); long current = start; while ((m_connectionList.size() == 0) && ((m_threadTimeout == 0) || ((current - start) < m_threadTimeout))) { wait(m_threadTimeout - (current - start)); current = System.currentTimeMillis(); }} catch (InterruptedException ex) { Thread.currentThread().interrupt();}if (m_connectionList.size() == 0) { connection = null;} else { connection = (Connection) m_connectionList.remove(0);}

Page 47: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● What happens if the thread is interrupted?

try { long start = System.currentTimeMillis(); long current = start; while ((m_connectionList.size() == 0) && ((m_threadTimeout == 0) || ((current - start) < m_threadTimeout))) { wait(m_threadTimeout - (current - start)); current = System.currentTimeMillis(); }} catch (InterruptedException ex) { Thread.currentThread().interrupt();}if (m_connectionList.size() == 0) { connection = null;} else { connection = (Connection) m_connectionList.remove(0);}

We catch it, but reset the interrupted flag, which effectively disables waiting.Why do this?

Page 48: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● What happens if the thread is interrupted?

try { long start = System.currentTimeMillis(); long current = start; while ((m_connectionList.size() == 0) && ((m_threadTimeout == 0) || ((current - start) < m_threadTimeout))) { wait(m_threadTimeout - (current - start)); current = System.currentTimeMillis(); }} catch (InterruptedException ex) { Thread.currentThread().interrupt();}if (m_connectionList.size() == 0) { connection = null;} else { connection = (Connection) m_connectionList.remove(0);}

It is related to how threads die when the

thread pool is stopping...

Page 49: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● Returning to the pseudo code, we can expand on when a thread dies.

// This is pseudo code for presentation purposes

private void processConnections() { Connection connection; while (true) { synchronized (this) { m_threadAvailable++; connection = waitForConnection(); m_threadAvailable--; if (shouldThreadDie(connection)) return; } try { connection.process(); } catch (SocketTimeoutException ex) { /* Log */ } } catch (IOException ex) { /* Log */ } }}

Page 50: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● The pseudo code expands to the following...

if (connection == null) { m_threadCount--; if ((m_state == STOPPING_STATE) && (m_threadCount == 0)) { m_shutdownGate.open(); m_shutdownGate = null; m_state = INACTIVE_STATE; } return;}

Page 51: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● The pseudo code expands to the following...which means what?

if (connection == null) { m_threadCount--; if ((m_state == STOPPING_STATE) && (m_threadCount == 0)) { m_shutdownGate.open(); m_shutdownGate = null; m_state = INACTIVE_STATE; } return;}

Page 52: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● The pseudo code expands to the following...which means what?

if (connection == null) { m_threadCount--; if ((m_state == STOPPING_STATE) && (m_threadCount == 0)) { m_shutdownGate.open(); m_shutdownGate = null; m_state = INACTIVE_STATE; } return;}

When a thread's timeout expires and

there are no connections, then it

kills itself.

Page 53: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● So, how does that explain why we use Thread.interrupt() to effectively eliminate waiting?

if (connection == null) { m_threadCount--; if ((m_state == STOPPING_STATE) && (m_threadCount == 0)) { m_shutdownGate.open(); m_shutdownGate = null; m_state = INACTIVE_STATE; } return;}

Page 54: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● So, how does that explain why we want Thread.interrupt() to effectively eliminate waiting?

if (connection == null) { m_threadCount--; if ((m_state == STOPPING_STATE) && (m_threadCount == 0)) { m_shutdownGate.open(); m_shutdownGate = null; m_state = INACTIVE_STATE; } return;}

If the thread no longer waits, it will effectively timeout

immediately and kill itself.

Page 55: Lecture 15: Simple Java Web Server

Thread Pool Thread HandlingThread Pool Thread Handling

● We will return to this when we discuss shutdown...

if (connection == null) { m_threadCount--; if ((m_state == STOPPING_STATE) && (m_threadCount == 0)) { m_shutdownGate.open(); m_shutdownGate = null; m_state = INACTIVE_STATE; } return;}

Page 56: Lecture 15: Simple Java Web Server

Thread Pool Connection ProcessingThread Pool Connection Processing

● Returning to the pseudo code, how does a thread pool thread process a connection?

// This is pseudo code for presentation purposes

private void processConnections() { Connection connection; while (true) { synchronized (this) { m_threadAvailable++; connection = waitForConnection(); m_threadAvailable--; if (shouldThreadDie(connection)) return; } try { connection.process(); } catch (SocketTimeoutException ex) { /* Log */ } } catch (IOException ex) { /* Log */ } }}

Page 57: Lecture 15: Simple Java Web Server

Thread Pool Connection ProcessingThread Pool Connection Processing

● Returning to the pseudo code, how does a thread pool thread process a connection?

// This is pseudo code for presentation purposes

private void processConnections() { Connection connection; while (true) { synchronized (this) { m_threadAvailable++; connection = waitForConnection(); m_threadAvailable--; if (shouldThreadDie(connection)) return; } try { connection.process(); } catch (SocketTimeoutException ex) { /* Log */ } } catch (IOException ex) { /* Log */ } }}

?

Page 58: Lecture 15: Simple Java Web Server

Thread Pool Connection ProcessingThread Pool Connection Processing

● Pseudo code for Connection.process():public void process() throws IOException { HttpRequest req = new HttpRequest(); HttpResponse res = new HttpResponse(m_server, req); try { // Loop until we close the connection. boolean close = false; while (!close) { // Read the next request. req.parseRequestLine(m_is); req.parseHeaderLines(m_is); req.parseBody(m_is); m_requestCount++; if (m_requestCount >= m_requestLimit) { close = true; } res.sendFileOrDirectory(m_os, close); } } finally { // Close socket and streams. }}

Page 59: Lecture 15: Simple Java Web Server

Thread Pool Connection ProcessingThread Pool Connection Processing

● How is this related to threading/concurrency?public void process() throws IOException { HttpRequest req = new HttpRequest(); HttpResponse res = new HttpResponse(m_server, req); try { // Loop until we close the connection. boolean close = false; while (!close) { // Read the next request. req.parseRequestLine(m_is); req.parseHeaderLines(m_is); req.parseBody(m_is); m_requestCount++; if (m_requestCount >= m_requestLimit) { close = true; } res.sendFileOrDirectory(m_os, close); } } finally { // Close socket and streams. }}

Page 60: Lecture 15: Simple Java Web Server

Thread Pool Connection ProcessingThread Pool Connection Processing

● How is this related to threading/concurrency?public void process() throws IOException { HttpRequest req = new HttpRequest(); HttpResponse res = new HttpResponse(m_server, req); try { // Loop until we close the connection. boolean close = false; while (!close) { // Read the next request. req.parseRequestLine(m_is); req.parseHeaderLines(m_is); req.parseBody(m_is); m_requestCount++; if (m_requestCount >= m_requestLimit) { close = true; } res.sendFileOrDirectory(m_os, close); } } finally { // Close socket and streams. }}

Since clients can send multiple

requests, we limit the number so they

cannot hog a thread.

Page 61: Lecture 15: Simple Java Web Server

Thread Pool Connection ProcessingThread Pool Connection Processing

● What happens if a client hangs?public void process() throws IOException { HttpRequest req = new HttpRequest(); HttpResponse res = new HttpResponse(m_server, req); try { // Loop until we close the connection. boolean close = false; while (!close) { // Read the next request. req.parseRequestLine(m_is); req.parseHeaderLines(m_is); req.parseBody(m_is); m_requestCount++; if (m_requestCount >= m_requestLimit) { close = true; } res.sendFileOrDirectory(m_os, close); } } finally { // Close socket and streams. }}

Page 62: Lecture 15: Simple Java Web Server

Thread Pool Connection ProcessingThread Pool Connection Processing

● What happens if a client hangs?public void process() throws IOException { HttpRequest req = new HttpRequest(); HttpResponse res = new HttpResponse(m_server, req); try { // Loop until we close the connection. boolean close = false; while (!close) { // Read the next request. req.parseRequestLine(m_is); req.parseHeaderLines(m_is); req.parseBody(m_is); m_requestCount++; if (m_requestCount >= m_requestLimit) { close = true; } res.sendFileOrDirectory(m_os, close); } } finally { // Close socket and streams. }}

We set a timeout on our client socket so our thread resumes if the client takes too long, which is why we

catch a timeout exception in ThreadPool.process

Connections().

Page 63: Lecture 15: Simple Java Web Server

Thread GateThread Gate

● For stopping both the server and thread pool we use a gate...what is it?

public class ThreadGate { private boolean m_open = false;

public synchronized void open() { m_open = true; notifyAll(); }

public synchronized void await() throws InterruptedException { while (!m_open) { wait(); } }}

Page 64: Lecture 15: Simple Java Web Server

Thread GateThread Gate

● For stopping both the server and thread pool we use a gate...what is it?

public class ThreadGate { private boolean m_open = false;

public synchronized void open() { m_open = true; notifyAll(); }

public synchronized void await() throws InterruptedException { while (!m_open) { wait(); } }}

Similar to a semaphore with an initial value of zero, but

where up() makes the value infinity, i.e, down()

will always succeed.

Page 65: Lecture 15: Simple Java Web Server

Web Server ShutdownWeb Server Shutdown

● What happens when we stop HttpServer?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if (m_shutdownGate == null) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; try { m_serverSocket.close(); } catch (IOException ex) { } } } if (gate != null) { gate.await(); }}

Page 66: Lecture 15: Simple Java Web Server

Web Server ShutdownWeb Server Shutdown

● What happens when we stop HttpServer?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if (m_shutdownGate == null) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; try { m_serverSocket.close(); } catch (IOException ex) { } } } if (gate != null) { gate.await(); }}

Simple case, if the server is already

stopped, then ignore...

Page 67: Lecture 15: Simple Java Web Server

Web Server ShutdownWeb Server Shutdown

● How do we actually tell the server to stop?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if (m_shutdownGate == null) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; try { m_serverSocket.close(); } catch (IOException ex) { } } } if (gate != null) { gate.await(); }}

Page 68: Lecture 15: Simple Java Web Server

Web Server ShutdownWeb Server Shutdown

● How do we actually tell the server to stop?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if (m_shutdownGate == null) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; try { m_serverSocket.close(); } catch (IOException ex) { } } } if (gate != null) { gate.await(); }}

We close the socket it is using to listen for connections.

Why?

Page 69: Lecture 15: Simple Java Web Server

Web Server ShutdownWeb Server Shutdown

● How do we actually tell the server to stop?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if (m_shutdownGate == null) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; try { m_serverSocket.close(); } catch (IOException ex) { } } } if (gate != null) { gate.await(); }}

The server thread is waiting on ServerSocket.accept() for new connections, but this

is not interruptible.

Page 70: Lecture 15: Simple Java Web Server

Web Server ShutdownWeb Server Shutdown

● What happens if multiple threads try to stop the server at the same time?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if (m_shutdownGate == null) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; try { m_serverSocket.close(); } catch (IOException ex) { } } } if (gate != null) { gate.await(); }}

Page 71: Lecture 15: Simple Java Web Server

Web Server ShutdownWeb Server Shutdown

● What happens if multiple threads try to stop the server at the same time?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if (m_shutdownGate == null) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; try { m_serverSocket.close(); } catch (IOException ex) { } } } if (gate != null) { gate.await(); }}

Only the first succeeds and creates a gate on

which it and subsequent threads will wait for the

server to stop.

Page 72: Lecture 15: Simple Java Web Server

Web Server ShutdownWeb Server Shutdown

● Why is the gate captured in a local variable?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if (m_shutdownGate == null) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; try { m_serverSocket.close(); } catch (IOException ex) { } } } if (gate != null) { gate.await(); }}

Page 73: Lecture 15: Simple Java Web Server

Web Server ShutdownWeb Server Shutdown

● Why is the gate captured in a local variable?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if (m_shutdownGate == null) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; try { m_serverSocket.close(); } catch (IOException ex) { } } } if (gate != null) { gate.await(); }}

Because we need to wait on the gate, but we must

do that outside the synchronized block...

Page 74: Lecture 15: Simple Java Web Server

Web Server ShutdownWeb Server Shutdown

● Why is the gate captured in a local variable?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if (m_shutdownGate == null) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; try { m_serverSocket.close(); } catch (IOException ex) { } } } if (gate != null) { gate.await(); }}

Additionally, since the server can be stopped and

restarted, we cannot assume that the value of

gate does not change.

Page 75: Lecture 15: Simple Java Web Server

Web Server ShutdownWeb Server Shutdown

● What happens if the calling thread is interrupted while waiting on the gate?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if (m_shutdownGate == null) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; try { m_serverSocket.close(); } catch (IOException ex) { } } } if (gate != null) { gate.await(); }}

Page 76: Lecture 15: Simple Java Web Server

Web Server ShutdownWeb Server Shutdown

● What happens if the calling thread is interrupted while waiting on the gate?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if (m_shutdownGate == null) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; try { m_serverSocket.close(); } catch (IOException ex) { } } } if (gate != null) { gate.await(); }}

It is released from the gate and exits the stop() method via an InterruptedException,

but the server continues shutting down.

Page 77: Lecture 15: Simple Java Web Server

Web Server ShutdownWeb Server Shutdown

● Returning to the server thread, what happens when the server socket is closed?

private void acceptConnections() { m_threadPool.start(); Socket socket; while (m_serverSocket.isBound() && !m_serverSocket.isClosed()) { try { socket = m_serverSocket.accept(); try { Connection connection = new Connection( this, socket, m_connectionTimeout, m_connectionRequestLimit); m_threadPool.addConnection(connection); } catch (IOException ex) { /* Log */ } } catch (IOException ex) { /* Log */ } } shutdown();}

Page 78: Lecture 15: Simple Java Web Server

Web Server ShutdownWeb Server Shutdown

● Returning to the server thread, what happens when the server socket is closed?

private void acceptConnections() { m_threadPool.start(); Socket socket; while (m_serverSocket.isBound() && !m_serverSocket.isClosed()) { try { socket = m_serverSocket.accept(); try { Connection connection = new Connection( this, socket, m_connectionTimeout, m_connectionRequestLimit); m_threadPool.addConnection(connection); } catch (IOException ex) { /* Log */ } } catch (IOException ex) { /* Log */ } } shutdown();}

It exits its loop and invokes shutdown() on the server instance.

Page 79: Lecture 15: Simple Java Web Server

Web Server ShutdownWeb Server Shutdown

● What does HttpServer.shutdown() do?

private void shutdown() { while (true) { try { m_threadPool.stop(); break; } catch (InterruptedException ex) { } }

synchronized (this) { m_shutdownGate.open(); m_shutdownGate = null; m_state = INACTIVE_STATE; }}

Page 80: Lecture 15: Simple Java Web Server

Web Server ShutdownWeb Server Shutdown

● What does HttpServer.shutdown() do?

private void shutdown() { while (true) { try { m_threadPool.stop(); break; } catch (InterruptedException ex) { } }

synchronized (this) { m_shutdownGate.open(); m_shutdownGate = null; m_state = INACTIVE_STATE; }}

It tells the thread pool to stop and waits for it.

Page 81: Lecture 15: Simple Java Web Server

Web Server ShutdownWeb Server Shutdown

● What does HttpServer.shutdown() do?

private void shutdown() { while (true) { try { m_threadPool.stop(); break; } catch (InterruptedException ex) { } }

synchronized (this) { m_shutdownGate.open(); m_shutdownGate = null; m_state = INACTIVE_STATE; }}

Once the thread pool has stopped, then it releases any threads

waiting for the HTTP server to stop.

Page 82: Lecture 15: Simple Java Web Server

Thread Pool ShutdownThread Pool Shutdown

● What happens when we stop ThreadPool?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if ((m_shutdownGate == null) && (m_threadCount > 0)) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; m_state = STOPPING_STATE; m_group.interrupt(); } } if (gate != null) { gate.await(); }}

Page 83: Lecture 15: Simple Java Web Server

Thread Pool ShutdownThread Pool Shutdown

● What happens when we stop ThreadPool?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if ((m_shutdownGate == null) && (m_threadCount > 0)) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; m_state = STOPPING_STATE; m_group.interrupt(); } } if (gate != null) { gate.await(); }}

Pretty much identical to stopping the HTTP server,

except...

Page 84: Lecture 15: Simple Java Web Server

Thread Pool ShutdownThread Pool Shutdown

● What happens when we stop ThreadPool?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if ((m_shutdownGate == null) && (m_threadCount > 0)) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; m_state = STOPPING_STATE; m_group.interrupt(); } } if (gate != null) { gate.await(); }}

Except we interrupt all thread pool threads. Why?

Page 85: Lecture 15: Simple Java Web Server

Thread Pool ShutdownThread Pool Shutdown

● What happens when we stop ThreadPool?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if ((m_shutdownGate == null) && (m_threadCount > 0)) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; m_state = STOPPING_STATE; m_group.interrupt(); } } if (gate != null) { gate.await(); }}

We want to interrupt all thread pool threads to

disable waiting so they kill themselves quickly.

Page 86: Lecture 15: Simple Java Web Server

Thread Pool ShutdownThread Pool Shutdown

● What happens when we stop ThreadPool?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if ((m_shutdownGate == null) && (m_threadCount > 0)) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; m_state = STOPPING_STATE; m_group.interrupt(); } } if (gate != null) { gate.await(); }}

The calling thread then waits for the thread pool to

stop. Who opens the gate?

Page 87: Lecture 15: Simple Java Web Server

Thread Pool ShutdownThread Pool Shutdown

● What happens when we stop ThreadPool?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if ((m_shutdownGate == null) && (m_threadCount > 0)) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; m_state = STOPPING_STATE; m_group.interrupt(); } } if (gate != null) { gate.await(); }}

This is handled when thread pool threads die; the last thread to die opens the

gate.

Page 88: Lecture 15: Simple Java Web Server

Thread Pool ShutdownThread Pool Shutdown

● So when actually does the server stop?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if ((m_shutdownGate == null) && (m_threadCount > 0)) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; m_state = STOPPING_STATE; m_group.interrupt(); } } if (gate != null) { gate.await(); }}

Page 89: Lecture 15: Simple Java Web Server

Thread Pool ShutdownThread Pool Shutdown

● So when actually does the server stop?

public void stop() throws InterruptedException { ThreadGate gate = null; synchronized (this) { if (m_state != INACTIVE_STATE) { if ((m_shutdownGate == null) && (m_threadCount > 0)) { m_shutdownGate = new ThreadGate(); } gate = m_shutdownGate; m_state = STOPPING_STATE; m_group.interrupt(); } } if (gate != null) { gate.await(); }}

After all thread pool threads have finished

processing any existing connections.

Page 90: Lecture 15: Simple Java Web Server

SummarySummary

● This simple web server illustrates many sophisticated threading and concurrency issues

● It only used what we have learned about so far