Lab Exercises
- Exercise 1: ThreadPool (30 minutes)
- Exercise 2: Executors (30 minutes)
- Exercise 3: Callable and Future (30 minutes)
- Exercise 4: Semaphore(30 minutes)
- Exercise 5: Blocking queue (30 minutes)
- Homework Exercise (for people who are taking Sang Shin’s “Java Programming online course”)
Exercise 1: ThreadPoolExecutor
- Build and run a server that receives connection request (using ThreadPoolExecutor)
- Build and run two instances of clients
(1.1) Build and run a server that receives connection request (using ThreadPoolExecutor)
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select General under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in ServerUsingThreadPoolExecutor as project name.
- For Create Main Class field, type in ServerUsingThreadPoolExecutor. (Figure-1.10 below)
- Click Finish.
Figure-1.10: Create a new project
- Observe that ServerUsingThreadPoolExecutor project appears and IDE generated ServerUsingThreadPoolExecutor.java is displayed in the source editor window of NetBeans IDE.
2. Modify the IDE generated ServerUsingThreadPoolExecutor.java as shown in Code-1.11 below. Study the code by paying special attention to the bold fonted parts.
This class acts as a listener on an IP port and echo characters sent to it when a connection is made. This is similar in functionality to a web server type application. Since we want to be able to handle lots of short living connections simultaneously, we would create a separate thread of execution for each connection. Since thread creation is a costly operation to the JVM, the best way to achieve this is to create and use a pool of threads. A thread in this pool then can be re-used by a new connection when a previous connection is done with it.
For this example, we use an implementation of the Executor interface, ThreadPoolExecutor. To create a new instance of this, we must also first create a Queue to be used for the pool, which in this example is an ArrayBlockingQueue which provides a fixed sized, queue which is protected to ensure multiple threads can add items without contention problems.
import java.net.*; import java.io.*; import java.util.concurrent.*; public class ServerUsingThreadPoolExecutor { private final static int MAX_THREADS = 2; private final ServerSocket serverSocket; /** /* In order to create a pool of threads, we must first have a queue /* Now create a ThreadPool. The initial and maximum number of /** try { pool.execute(new ConnectionHandler(serverSocket.accept(), count++)); /** try { /* |
Code-1.11: ServerUsingThreadPoolExecutor.java
3. Write ConnectionHandler.java as shown in Code-1.12 below.
import java.io.*; import java.net.*; import java.util.concurrent.*; public class ConnectionHandler implements Runnable { /** /** try { // Loop to do something with the socket here /* If the number of bytes read is less than zero then the connection System.out.println(“[” + connectionID + “]: ” + new String(inData)); System.out.println(“Connection ” + connectionID + “, ended”); |
Code-1.12: ConnectionHandler.java
4. Build and run the project
- Right click ServerUsingThreadPoolExecutor project and select Run.
- Observe the result in the Output window. (Figure-1.13 below) The server is waiting for connection request from clients.
Listening for connections… |
Figure-1.13: Result of running ServerUsingThreadPoolExecutor application
Trouble-shooting: If you see the following error condition, it is highly likely due to the fact that you have not terminate the server process that uses the same port – port 8100 in this example.
IO Error creating listener: Address already in use: JVM_Bind |
Solution: Terminate the previously started process that uses the same port. Click Runtime tab window and expand Processes node and then right click the process and select Terminate Process. Or as a brutal method, exiting the NetBeans IDE will do it as well. Also you can use the different port number other than 8100. In this case, you will also need to change the hard-coded port number of the client.
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5concurrency/samples/ServerUsingThreadPoolExecutor. You can just open it and run it.
(1.2) Build and run two instances of ConnectionClient
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select General under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in ConnectionClient as project name.
- For Create Main Class field, type in ConnectionClient.
- Click Finish.
- Observe that ConnectionClient project appears and IDE generated ConnectionClient.java is displayed in the source editor window of NetBeans IDE.
2. Modify the IDE generated ConnectionClient.java as shown in Code-1.21 below. Study the code by paying special attention to the bold fonted parts.
import java.net.*; import java.io.*; import java.util.concurrent.*; /** /** if (args.length < 2) { OutputStream os = null; try { /* Read data from the standard input and send it to the remote socket */ System.in.read(inData); if (inString.substring(0, 4).compareTo(“EXIT”) == 0) os.write(inData); |
Code-1.21: ConnectionClient.java
3. Build and run the project
- Right click ConnectionClient project and select Run.
- Observe the result in the Output window. (Figure-1.23 below)
Connection established to server. Type characters and press <ENTER> to send Type EXIT and press <RETURN> to exit |
Figure-1.23: Result of running ConnectionClient application
- Enter some value into the Input field and press Enter key. (Figure-1.25 below) In this example below, “This is a message from ConnectionClient instance 1” is entered.
Figure-1.25: Enter a message
Trouble-shooting: If you see the following error condition, it is highly likely due to the fact that you have not started the server or firewall blocks the connection request.
Failed to connect to remote host: Connection refused: connect |
Solution: Start the server. Also disable firewall on your computer,
4. Observe the output on the server side.
- Click the ServerUsingThreadPoolExecutor tab window to see the output of the ServerUsingThreadPoolExecutor.
- Observe that the message it received from ConnectionClient is displayed. (Figure-1.26 below)
Figure-1.26: Connection request from ConnectionClient is received and message from ConnectionClient is displayed
5. Build and run another instance of ConnectionClient.
- Right click ConnectionClient project and select Run. This will start the 2nd instance of the ConnectionClient.
- Observe the result in the Output window has a ConnectionClient (run) #2 tab. (Figure-1.23 below)
Connection established to server. Type characters and press <ENTER> to send Type EXIT and press <RETURN> to exit |
Figure-1.23: Result of running ConnectionClient application
- Enter some value and press Enter key. (Figure-1.27 below) In this example, “Message from the 2nd instance of ConnectionClient by Sang Shin” is entered.
Figure-1.27: Enter data from the 2nd instance of ConnectionClient
6. Observe the output on the server side.
- Click the ServerUsingThreadPoolExecutor tab window to see the output of the ServerUsingThreadPoolExecutor.
- Observe that the message it received fromthe 2nd instance ConnectionClient is displayed. (Figure-1.28 below)
Figure-1.28: Connection request from ConnectionClient is received and message from ConnectionClient is displayed
7. Close NetBeans in order to terminate the ServerUsingThreadPoolExecutor and ConnectionClient processes for subsequent exercises. If you skip this, you will get IO Error creating listener: Address already in use: JVM_Bind later on when you run a server program that shares the same port number.
Figure-1.29: Exit NetBeans IDE to terminate the processes
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5concurrency/samples/ConnectionClient. You can just open it and run it.
Summary
Exercise 2: Implement Runnable interface
In this exercise, you are going to rewrite the ServerUsingThreadPoolExecutor code to use the Executors utility class. We will rename the file to ServerUsingExecutors.
(2.1) Build and run a server that receives connection requests (using Executors)
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select General under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in ServerUsingExecutors as project name.
- For Create Main Class field, type in ServerUsingExecutors.
- Click Finish.
- Observe that ServerUsingExecutors project appears and IDE generated ServerUsingExecutors.java is displayed in the source editor window of NetBeans IDE.
2. Modify the IDE generated ServerUsingExecutors.java as shown in Code-2.11 below. Study the code by paying special attention to the bold fonted parts.
import java.net.*; import java.io.*; import java.util.concurrent.*; public class ServerUsingExecutors { private final ServerSocket serverSocket; public ServerUsingExecutors(int port, int poolSize) throws IOException { /* Use the Exectors factory method to get a ThreadPool */ } /** try { } public static void main(String[] args) { try { |
Code-2.11: ServerUsingExecutors.java
3. Write ConnectionHandler.java as shown in Code-2.12 below. This is the same code you’ve created in the Exercise 1 above.
import java.io.*; import java.net.*; import java.util.concurrent.*; public class ConnectionHandler implements Runnable { /** /** try { // Loop to do something with the socket here /* If the number of bytes read is less than zero then the connection System.out.println(“[” + connectionID + “]: ” + new String(inData)); System.out.println(“Connection ” + connectionID + “, ended”); |
Code-2.12: PrintNameRunnable.java
4. Build and run the project
- Right click ServerUsingExecutors project and select Run.
- Observe the result in the Output window. (Figure-1.13 below) The server is waiting for connection request from clients.
Listening for connections… |
Figure-1.13: Result of running ServerUsingExecutors application
Trouble-shooting: If you see the following error condition, it is highly likely due to the fact that you have not terminate the server process that uses the same port – port 8100 in this example.
IO Error creating listener: Address already in use: JVM_Bind |
Solution: Terminate the previously started process that uses the same port. Exit the NetBeans IDE will do it. Also you can use the different port number other than 8100. In this case, you will also need to change the hard-coded port number of the client.
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5concurrency/samples/ServerUsingExecutors. You can just open it and run it.
(2.2) Create and start a thread by implementing Runnable interface – start() method is in the constructor
- Right click ConnectionClient project and select Run. This will start the 1st instance of the ConnectionClient.
- Observe the result in the Output window. (Figure-2.21 below)
Connection established to server. Type characters and press <ENTER> to send Type EXIT and press <RETURN> to exit |
Figure-2.21: Result of running ConnectionClient application
- Enter some value into the Input field and press Enter key.
2. Observe the output on the server side.
- Click the ServerUsingThreadPoolExecutor tab window to see the output of the ServerUsingThreadPoolExecutor.
- Observe that the message it received from the 1st instance ConnectionClient is displayed.
3. Build and run the 2nd instance of ConnectionClient.
- Right click ConnectionClient project and select Run. This will start the 2nd instance of the ConnectionClient.
- Observe the result in the Output window. (Figure-2.22 below)
Connection established to server. Type characters and press <ENTER> to send Type EXIT and press <RETURN> to exit |
Figure-2.22: Result of running ConnectionClient application
4. Observe the output on the server side.
- Click the ServerUsingThreadPoolExecutor tab window to see the output of the ServerUsingThreadPoolExecutor.
- Observe that the message it received from the 2nd instance ConnectionClient is displayed.
Summary
In this exercise, you learned how to use Executors utility class to create a pool of threads.
Exercise 3: Callable and Future
The Executors class contains utility methods to convert from other common forms to Callable classes.
(3.1) Callable and Future
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select General under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in CallableAndFuture as project name.
- For Create Main Class field, type in CallableAndFuture.
- Click Finish.
- Observe that CallableAndFuture project appears and IDE generated CallableAndFuture.java is displayed in the source editor window of NetBeans IDE.
2. Modify the IDE generated CallableAndFuture.java as shown in Code-3.11 below. Study the code by paying special attention to the bold fonted parts.
import java.util.concurrent.*;
/** /** /* Now attempt to run a task in the second thread */ /* Shutdown the second thread so the program terminates gracefully /** |
Code-3.11: CallableAndFuture.java
3. Write CallableExample.java as shown in Code-3.12 below. Study the code by paying special attention to the bold fonted parts.
import java.net.*; import java.io.*; import java.util.concurrent.*; /** try { System.out.println(“Completed call() method in second thread”); |
Code-3.12: SimpleThread.java
4. Build and run the project
- Right click CallableAndFuture project and select Run.
- Observe the result in the Output window. (Figure-3.13 below)
Starting test in first thread Starting call() method in second thread Completed call() method in second thread First thread work complete. Asking future for result Result from Future is Finished |
Figure-3.13: Result of running CallableAndFuture application
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javase5concurrency/samples/CallableAndFuture. You can just open it and run it.
Summary
Exercise 4: Semaphore
“Conceptually, a semaphore maintains a set of permits. Each acquire() blocks if necessary until a permit is available, and then takes it. Each release() adds a permit, potentially releasing a blocking acquirer. However, no actual permit objects are used; the Semaphore just keeps a count of the number available and acts accordingly.
Semaphores are often used to restrict the number of threads than can access some (physical or logical) resource.”
(4.1) Semaphore
1. Create a new NetBeans project
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select General under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in SemaphoreExample as project name.
- For Create Main Class field, type in ResourseUser.
- Click Finish.
- Observe that SemaphoreExample project appears and IDE generated ResourseUser.java is displayed in the source editor window of NetBeans IDE.
2. Modify the IDE generated ResourseUser.java as shown in Code-4.11 below.
This class creates three threads that try to access the two reources in the pool. By using a semaphore to restrict access to the resources, this demonstrates that one of the three threads will always block when trying to aquire a resource. The threads hold a resource for different lengths of time to illustrate this more clearly.
/** * * Concurrency utilities (JSR-166) example **/ import java.net.*; /** /** /** Thread.sleep(hold); /** /* Use the Executors utility class to get a new FixedThreadPool. /* Create three new resource users and start them using the previously /* Clean up the thread pool so the program terminates cleanly */ |
Code-4.11: ResourseUser.java
3. Write ResourcePool.java as shown in Code-4.12 below.
import java.net.*; import java.io.*; import java.util.concurrent.*; /** /** /* Create a pool of resources (for this example just a set of Integer used = new boolean[poolSize]; for (int i = 0; i < poolSize; i++) /** for (int i = 0; i < poolSize; i++) { return null; /** |
Code-4.12: PrintStringsThread.java
4. Build and run the project
- Right click SemaphoreExample project and select Run.
- Observe the result in the Output window. (Figure-4.14 below)
[1] trying to get resource [1] aquired resource [2] trying to get resource [2] aquired resource [3] trying to get resource [1] releasing resource [3] aquired resource [2] releasing resource [1] trying to get resource [1] aquired resource [2] trying to get resource [1] releasing resource [2] aquired resource [3] releasing resource [1] trying to get resource [1] aquired resource [3] trying to get resource [2] releasing resource [3] aquired resource [1] releasing resource [2] trying to get resource [2] aquired resource [1] trying to get resource [3] releasing resource [1] aquired resource [2] releasing resource [1] releasing resource [3] trying to get resource [3] aquired resource [2] trying to get resource [2] aquired resource [1] trying to get resource [2] releasing resource [1] aquired resource [3] releasing resource [1] releasing resource [2] trying to get resource [2] aquired resource [3] trying to get resource [3] aquired resource [2] releasing resource [3] releasing resource [3] trying to get resource [3] aquired resource [3] releasing resource |
Figure-4.14: Result of running SemaphoreExample application
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javathreads/samples/SemaphoreExample. You can just open it and run it.
5. For your own exercise, do the following.
Change the values used when creating the ResourceUser objects. For example make each ResourceUser hold the resource for the same duration. Recompile and run the application and see if the application behaves differently.
ResourceUser r1 = new ResourceUser(pool, 1, 5, 1000, 500); ResourceUser r2 = new ResourceUser(pool, 2, 5, 1000, 500); ResourceUser r3 = new ResourceUser(pool, 3, 5, 1000, 500); |
Summary
Exercise 5: Blocking queue
(5.1) Blocking queue example
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project pane, select General under Categories and Java Application under Projects.
- Click Next.
- Under Name and Location pane, for the Project Name field, type in BlockingQueueExample as project name.
- For Create Main Class field, type in BlockingQueueExample.
- Click Finish.
- Observe that BlockingQueueExample project appears and IDE generated BlockingQueueExample.java is displayed in the source editor window of NetBeans IDE.
2. Modify the IDE generated BlockingQueueExample.java as shown in Code-5.11 below.
The BlockingQueueExample class creates an ArrayBlockingQueue, which is the simplest concrete implementation of the BlockingQueue interface. It uses this to send messages to the Logger object.
import java.net.*; import java.io.*; import java.util.concurrent.*; /** /** /** /** /* For the test we will need a BlockingQueue to be used by both threads /* Use the utility method from the Executors class to get an /* Again use the utility Executors class to get a new ExecutorService |
Code-5.11: BlockingQueueExample.java
3. Write Logger.java as shown in Code-5.12 below. Study the code by paying special attention to the bold fonted parts.
The Logger class takes a BlockingQueue as an argument to the constructor to use as a queue to hold messages that need to be logged. The BlockingQueue will ensure thread safe operations when multiple threads are trying to add elements to the list.
import java.net.*; import java.io.*; import java.util.concurrent.*; /** private BlockingQueue<String> messageQueue; /** /** |
Code-5.12: Logger.java
4. Build and run the project
- Right click BlockingQueueExample project and select Run.
- Observe the result in the Output window. (Figure-5.15 below)
LOG MSG: ID 1: log message number 0 LOG MSG: ID 1: log message number 1 LOG MSG: ID 1: log message number 2 LOG MSG: ID 1: log message number 3 LOG MSG: ID 1: log message number 4 LOG MSG: ID 1: log message number 5 LOG MSG: ID 1: log message number 6 LOG MSG: ID 1: log message number 7 LOG MSG: ID 1: log message number 8 LOG MSG: ID 1: log message number 9 |
Figure-5.15: Result of running BlockingQueueExample application
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javathreads/samples/BlockingQueueExample. You can just open it and run it.
(5.2) Blocking queue example using multiple senders
- Create multiple instances of the MsgSender class with different identifiers and pause times
- Change the Executor to a ThreadPoolExecutor to support the right number of threads.
- Have the threads use different pauses between sending messages so you can see the interleaving of the different threads of execution.
1. Create a new NetBeans project called BlockingQueueExample2 by copying BlockingQueueExample project.
2. Modify the BlockingQueueExample.java as shown in Code-5.21 below.
import java.net.*; import java.io.*; import java.util.concurrent.*; /** /** /** /** /* For the test we will need a BlockingQueue to be used by both threads /* Use the utility method from the Executors class to get an /* Now create a new fixed size thread pool to allow us to run |
Code-5.21: Modified BlockingQueueExample.java
3. Build and run the project
- Right click BlockingQueueExample project and select Run.
- Observe the result in the Output window. (Figure-5.23 below)
LOG MSG: ID 1: log message number 0 LOG MSG: ID 1: log message number 1 LOG MSG: ID 1: log message number 2 LOG MSG: ID 1: log message number 3 LOG MSG: ID 1: log message number 4 LOG MSG: ID 1: log message number 5 LOG MSG: ID 1: log message number 6 LOG MSG: ID 1: log message number 7 LOG MSG: ID 1: log message number 8 LOG MSG: ID 1: log message number 9 |
Figure-5.23: Result of running BlockingQueueExample application
Solution: This exercise up to this point is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it as <LAB_UNZIPPED_DIRECTORY>/javathreads/samples/BlockingQueueExample2. You can just open it and run it.
Summary
Homework exercise (for people who are taking Sang Shin’s “Java Programming online course”)
- Increase the maximum thread size to 3 (instead of 2)
- Build and run 3 client instances (instead of 2)
- Zip file of the the MyServerUsingThreadPoolExecutor NetBeans project. (Someone else should be able to open and run it as a NetBeans project.) You can use your favorite zip utility or you can use “jar” utility that comes with JDK as following.
- cd <parent directory that contains MyServerUsingThreadPoolExecutor directory> (assuming you named your project as MyServerUsingThreadPoolExecutor)
- jar cvf MyServerUsingThreadPoolExecutor.zip MyServerUsingThreadPoolExecutor (MyServerUsingThreadPoolExecutor directory should contain nbproject directory)
- Captured output screen – name it as JavaIntro-javase5concurrency.gif orJavaIntro-javase5concurrency.jpg (or JavaIntro-javase5concurrency.<whatver graphics format>)
- Any screen capture that shows that your program is working is good enough. No cosmetic polishment is required.
- If you decide to use different IDE other than NetBeans, the zip file should contain all the files that are needed for rebuilding the project – war file with necessary source files is OK.