0% found this document useful (0 votes)
33 views

Week12 - Threads and Network Programming

The document discusses multithreading in Java. It provides examples of creating threads by extending the Thread class and implementing the Runnable interface. It demonstrates running multiple threads concurrently using start() and joining threads using join() to wait for threads to finish before continuing. The examples calculate sums of array elements by splitting the work across multiple threads.

Uploaded by

Ilhan Klisura
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
33 views

Week12 - Threads and Network Programming

The document discusses multithreading in Java. It provides examples of creating threads by extending the Thread class and implementing the Runnable interface. It demonstrates running multiple threads concurrently using start() and joining threads using join() to wait for threads to finish before continuing. The examples calculate sums of array elements by splitting the work across multiple threads.

Uploaded by

Ilhan Klisura
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 57

IBU CEN 221 | Object-Oriented

International Burch University


Programming with Java

Becir Isakovic
Lectures Schedule #1
Week 1 - User input, Printing on screen & Conditional statements

Week 2 - Loops & Basics of methods

Week 3 - Methods, ArrayList data structure, Streams and connecting to the database - Quiz 1

Week 4 - Basics of objects, Encapsulation and Inheritance

Week 5 - More on objects, Abstraction and Polymorphism - Quiz 2

Week 6 - Tables, Sorting & Searching, HashMap data structure, Generics

Week 7 - Lambda functions, Records, Optionals , final keyword, & Preparation for the Midterm Exam -
Quiz 3
Lectures Schedule #2
Week 8 & 9 - MIDTERM

Week 10 - Regular expressions, File Manipulation, Iterators, Reflection & Custom Annotations

Week 11 - Exceptions and Unit Testing

Week 12 - Network Programming & Threads (Quiz 4)

Week 13 - Design Patterns

Week 15 - Graphical user interface (GUI) - (Quiz 5)


Threads

- Multithreading is the ability of executing multiple different paths of code at the


same time
- Normally, your Java code is using a single thread, meaning that everything you
do is synchronized, however, you can run multiple threads that will complete
their respective tasks independently
- There are two ways to use multiple threads in Java
- By extending the Thread class
- By implementing the runnable interface
Threads

- The computer is able to do multiple tasks concurrently


- If the computer has multiple cores, it can execute multiple tasks depending on
how many cores it has (8 cores, 8 tasks concurrently)
- If it has only one core or if all of the cores are busy, it switches between the tasks
very fast, and you get the illusion that it executes the tasks concurrently while it
is not, but the processor mechanism is extremely fast
Threads example

- In the first example, we will extend the Thread class and override its run method
with the code that we want to be multi-threaded as follows
class CounterMultithreaded extends Thread {
@Override
public void run(){
for(int i = 0; i<=5; i++){
System.out.println(i);

try {
Thread.sleep(1000); // 1 second
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
Threads example cont.
- We also have the .sleep(milliseconds: long) method that pauses the thread for
specified number of milliseconds so we can see the thread execution process
- Now, we want to use this class so it works with multiple threads
- In order to do that we want to create a instance of the class previously created
and call the start() method on it
- That will create a new thread and execute the code that we have wrote in our run
method and go back to the execution of our main method
Threads example cont.
- If the thread calls the yield() method, the scheduler checks if there is any thread
on the ready state waiting to be executed, it moves the current thread to the
Ready state and gives the processor another task.
- yield() method is called on the Thread object and accepts no parameter and does
not return any output.
Threads example cont.
public static void main(String[] args) {
CounterMultithreaded counterMultithreaded = new CounterMultithreaded();
counterMultithreaded.start();
}

- Now, we will see in our console that it is writing the numbers from 0 to 4 where
we have a 1 second delay between each new line written to the console
- Now, let us create one more object instance and see that it is executing the
processes in parallel achieving the multithreading
Threads example cont.
public static void main(String[] args) {
CounterMultithreaded firstCounter = new CounterMultithreaded();
CounterMultithreaded secondCounter = new CounterMultithreaded();
firstCounter.start();
secondCounter.start();
}

- If we, on the other hand, call a run method, the threads will not make any sense
as the second thread will be executed only after the first one finishes processing
the run function, soo we want to use the start method instead as shown in both of
the previous examples
Threads example cont.
- If we want to have 5 threads working in a same time, we just want to iterate and
create them to assure ourselves that it is executing the code at the same time, and
that the each thread runs totally independently of the others

for (int i = 0; i<= 5;i++){


CounterMultithreaded counter = new CounterMultithreaded();
counter.start();
}
Threads example cont.
- Yes, we now know that this is a multithreaded application but we have no idea of
which thread is executing when the output is shown to the console
- Let us create a mechanism that will also show us which thread is executing at
certain point of time
- To do this let us create one variable in our previously defined class and create a
constructor that will initialize its value
- Also, we want to write to the console which thread executes that part of the code
Threads example cont.
class CounterMultithreaded extends Thread {
private int threadNumber;

public CounterMultithreaded(int threadNumber) {


this.threadNumber = threadNumber;
}

@Override
public void run() {
for (int i = 0; i <= 5; i++) {
System.out.println(i + " from thread " + this.threadNumber);
}
}
}
Threads example cont.
- Now, when we execute the code, we would expect these threads to run the
program in the same order in which they have been created
- But that is not true, the threads are executing every time in a different order
- This tells us that, once we have multiple threads we cannot guarantee the order of
which the threads will be executed
- They are all running in the same time, completely independently one of the other
- One great advantage of using a threads is that, if the exception occurs in one of
these, it will not affect the others
Threads with interface
- As specified at the beginning of the presentation, we can also create the threads
by implementing the interface Runnable
- What is great is that the only thing we would be doing is the same as we have
done by extending the Thread class, we want to provide our own implementation
of the run method, as previously
- However, once we want to run our thread there is a slight difference as we have
to create a new Thread and pass our previously created class that implements
Runnable interface as a constructor parameter and use the start method on the
Thread object as shown in the following code
Threads with interface example
class CounterMultithreaded implements Runnable {
// Rest of the code is unchanged
}

public static void main(String[] args) {


for (int i = 0; i<= 5;i++){
CounterMultithreaded counter = new CounterMultithreaded(i);
Thread thread = new Thread(counter);
thread.start();
}
}
- The code is pretty similar to what we had previously
Threads
- There is one advantage of using the Runnable interface over the Thread class
- Once we extend one class we cannot extend any other, while if we can implement
as many interfaces as we would like
Thread joining
- What if we want to join the result of our threads, meaning that we want to wait
for one thread to finishes its job before performing another job
- For example, let us say we have a huge array of numbers that we want to
calculate the sum for and we want to use the threads to accomplish this job
- We will be using the .join() method in our multithreaded program that will wait
for the threads to execute and then combine their results as shown in the example
below
Thread joining
- The join() method causes the current thread (the one on which join() is called) to
wait until the thread it is called on (the thread being joined) completes its
execution.
- The join() method is particularly useful in scenarios where you have multiple
threads running concurrently, and you want one thread to wait for another thread
to complete its execution before proceeding.
Thread joining example
public class SumMultithreaded { // Wait for all threads to finish
for (Thread thread : threads) {
private static final int ARRAY_SIZE = 100_000_000;
private static final int NUM_THREADS = 4; try {
private static int calculateSumMultiThreaded() { thread.join();
} catch (InterruptedException e) {
int[] partialSums = new int[NUM_THREADS]; e.printStackTrace();
Thread[] threads = new Thread[NUM_THREADS]; }
}
for (int i = 0; i < NUM_THREADS; i++) {
final int threadIndex = i;
threads[i] = new Thread(() -> { // Combine partial sums
int partialSum = 0; int sum = 0;
for (int j = threadIndex; j < ARRAY_SIZE; j += NUM_THREADS){ for (int partialSum : partialSums) {
partialSum += array[j]; sum += partialSum;
}
partialSums[threadIndex] = partialSum;
}
}); return sum;
threads[i].start();
}
Thread joining example cont.
- In the previous example, we have initialized 4 different threads and we have
splitted the work of calculating the sum of array values between them
- After all of the threads finished their job of calculating the partial sum, we have
invoked the .join() method (waits for the thread to finish before continue
execution the program)
- After all of the threads finished their work, the partials sums are then combined
into a single sum
- Run the program, and assure yourself that even on this small problem, the
multithreaded function will perform better than the single threaded
Thread joining example cont.
- In order to calculate the time needed for specific task to be executed you can use
the System.currentTimeMillis() that returns the current milliseconds

long startTime = System.currentTimeMillis();


long endTime = System.currentTimeMillis();
long executionTime = endTime - startTime;
Thread synchronization
- Now, let's discuss thread synchronization. In multithreading, when multiple
threads access shared resources simultaneously, there is a possibility of data
inconsistency.
- Synchronization ensures that only one thread can access the shared resource at a
time.
- Java provides the synchronized keyword for this purpose.
- Let us look at the example of thread synchronization, debug it, and make some
conclusions
Thread synchronization example
- First let us create a new Counter class that has a synchronous methods (single
thread can access it at certain point of time)
class CounterSync {
private int count = 0;

public synchronized void increment() {


count++;
}

public int getCount() {


return count;
}
}
Thread synchronization example
class SynchronizationExample { t1.start();
public static void main(String[] args) { t2.start();
CounterSync counter = new
CounterSync(); try {
t1.join();
Thread t1 = new Thread(() -> { t2.join();
for (int i = 0; i < 10000; i++) { } catch (InterruptedException e) {
counter.increment(); e.printStackTrace();
} }
});
System.out.println("Count: " +
Thread t2 = new Thread(() -> { counter.getCount());
for (int i = 0; i < 10000; i++) { }
counter.increment(); }
}
});
Thread synchronization example explained
- In this example, the increment method and getCount method in the Counter class are
synchronized using the synchronized keyword.
- This ensures that only one thread can execute these methods at a time, preventing data
inconsistency.
- The join() method is used to wait for the completion of both threads before printing
the final count.
- If you run the same example without using the synchronized keyword, you will see all
sort of different results and the outcome is totally different for each run
- This is due to the fact that we have no idea how threads will execute their job is they
are no synchronized
Thread pools - Executor service
- In some cases, we do not want to have any classes that extends the Thread class as we
do not have any other attributes in it
- We only want to use the multithreaded approach in executing some task
- In that case, we want to create a pool of threads that will execute a certain task and
shut them down after they finish
- In Java, an ExecutorService thread pool is a mechanism provided by the
java.util.concurrent package to manage and reuse a pool of worker threads for
executing tasks concurrently. Instead of creating a new thread for each task, which can
be inefficient due to the overhead of thread creation and destruction, an
ExecutorService maintains a pool of threads that can be reused for multiple tasks.
Executor service example
class ExecutorServiceExample { class RunnableTask implements Runnable {
private final String taskName;
public static void main(String[] args) {
ExecutorService executorService = public RunnableTask(String taskName) {
Executors.newFixedThreadPool(3); this.taskName = taskName;
}
for (int i = 1; i <= 5; i++) {
RunnableTask task = new @Override
RunnableTask("Task " + i); public void run() {
executorService.submit(task); System.out.println("Executing " +
} taskName + " on thread " +
Thread.currentThread().getName());
executorService.shutdown(); }
} }
}
Network programming

- A URL, or Uniform Resource Locator, is a reference or address used to access


resources on the internet. It serves as a way to locate and retrieve information on
the web.
- URLs are essential for navigating the internet and accessing web resources,
including websites, documents, images, and other types of files.
URL parts

- URL consists of following segments:


- Scheme: It indicates the protocol used to access the resource. Common schemes include "http," "https,"
"ftp," etc.
- Domain: This is the human-readable address of the server hosting the resource. For example, in the URL
"https://www.example.com," "www.example.com" is the domain.
- Path: It specifies the location of a specific resource on the server. For instance, in the URL
"https://www.example.com/page1," "/page1" is the path.
- Query Parameters: These are additional parameters or data appended to the URL, usually used to pass
information to the server. They are separated from the rest of the URL by a question mark (?).
- Fragment Identifier: It points to a specific section within the resource. It is separated from the rest of the
URL by a hash (#).
URL example

- Let us a develop a program that will read from na URL and get the protocol and
authority that is responsible for the webpage
public static void readUrl(String urlAddress) {
try {
URL url = new URL(urlAddress);
System.out.println("URL is ok, protocol used is " +
url.getProtocol() + ", and the authority " + url.getAuthority());
} catch (MalformedURLException e) {
System.out.println("String " + urlAddress + " is not a valid URL");
}
}
Reading data from webpage

- We are able to communicate with the actual resource on the web by using the
URL class and get the authority and the protocol used
- What if we want to get the content of the webpage
- We will be using the BufferedReader that we have been using previously while
reading from the file, but now the source is the url stream
- After we get all of the information from the website, we are then iterating
through it in order to read it line by line
Reading data from URL example
public static void readPageData(String urlAddress) throws IOException {
URL url = new URL(urlAddress);
BufferedReader inputStream = new BufferedReader(
new InputStreamReader(url.openStream(),
StandardCharsets.UTF_8)
);
String content = "";
String line = null;
while ((line = inputStream.readLine()) != null)
content = content + line;
}
Reading data from URL example cont.

- We have used the https://klix.ba url and we were able to scrap that website by
using the url
- But let us create a more useful application and when we read all data from this
web portal let us use the regex expressions in order to extract the article titles
from the content we have just crawled
- This is extremely widely used approach for scraping the websites
Reading data from URL example with regex
String pattern = "<h2[^>]*>(.*?)</h2>";

Pattern regex = Pattern.compile(pattern, Pattern.DOTALL);


Matcher matcher = regex.matcher(content);

while (matcher.find()) {
String h2Content = matcher.group(1);
System.out.println("Matched h2 content: " + h2Content);
}
XML

- XML, or eXtensible Markup Language, is a markup language that defines a set of


rules for encoding documents in a format that is both human-readable and
machine-readable.
- It was designed to be a simple and flexible way to store and transport data.
- XML is widely used for representing structured data and is a predecessor to
JSON.
- While XML remains in use, JSON has become more popular in recent years for
certain applications due to its simplicity and conciseness, especially in web
development and APIs.
XML example

- The choice between XML and JSON often depends on the specific requirements
and conventions of a given application or system.
<person>
<name>John Doe</name>
<age>30</age>
<city>New York</city>
<isStudent>false</isStudent>
<courses>
<course>Math</course>
<course>History</course>
<course>English</course>
</courses>
</person>
JSON

- JSON, or JavaScript Object Notation, is a lightweight data interchange format


that is easy for humans to read and write, and easy for machines to parse and
generate.
- It is a text format that is often used to transmit data between a server and a web
application, as an alternative to XML (eXtensible Markup Language).
- Data is represented in name/value pairs.
- Data objects are enclosed in curly braces {}.
- Each data member is separated by a comma.
- Arrays are ordered lists and are enclosed in square brackets [].
JSON cont.

- JSON is widely used for configuration files, data storage, and communication
between a server and a client in web development. Its simplicity and ease of use
make it a popular choice for these purposes.
{
"name":"John Doe",
"age":30,
"city":"New York",
"isStudent":false,
"courses":[
"Math",
"History",
"English"
]
}
Reading JSON in Java

- In order to use JSON format in the Java application we will add one dependency
to our pom.xml file called json

<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20231013</version>
</dependency>
Reading JSON in Java cont.

- Let us create a small method that will read the JSON string to the actual json
object
- We can use the method called getString that will extract the value for a key you
pass as a parameter

public static void readSimpleJson() {


String json = "{ \"key\": \"value\" }";
JSONObject jsonObject = new JSONObject(json);
System.out.println(jsonObject);
System.out.println(jsonObject.getString("key"));
}
Reading JSON in Java from URL

- Let us now utilize the previously gained knowledge to read the json from the
URL
- We will use the following online tool to generate the simple JSON and use the
URL to access this resource (https://jsonbin.io/quick-store/)
- In here there is also a two methods that we can use, first getJSONObject(key:
String), to obtain the object and also the getJSONArray(key: String) to obtain the
array from the JSON
Reading JSON in Java from URL cont.
public static void readJson(String urlAddress) throws IOException {
URL url = new URL(urlAddress);
BufferedReader inputStream = new BufferedReader(
new InputStreamReader(url.openStream(), StandardCharsets.UTF_8)
);
String content = "";
String line = null;
while ((line = inputStream.readLine()) != null)
content = content + line;

JSONObject jsonObject = new JSONObject(content);


System.out.println(jsonObject.getJSONObject("record").getJSONArray("likes"));
}
HTTP

- HTTP, or Hypertext Transfer Protocol, is an application-layer protocol that


facilitates communication between web browsers and web servers.
- It is the foundation of data communication on the World Wide Web and is used
for transferring hypertext, which typically includes HTML documents.
- HTTP defines several methods (or verbs) that indicate the desired action to be
performed on a resource.
- These methods are part of the request sent by the client to the server.
HTTP methods

- The most commonly used HTTP methods are:


- GET: Requests data from a specified resource.
- POST: Submits data to be processed to a specified resource. It can result in the creation of a
new resource or an update of existing resources on the server.
- PUT: Updates a specified resource
- DELETE: Requests the removal of a specified resource.
- PATCH: Applies partial modifications to a resource.
- HEAD: Requests the headers of a specified resource without the actual data, useful for
checking the status of a resource.
- OPTIONS: Requests information about the communication options available for a specified
resource.
HTTP methods cont.

- These methods provide a way for clients to interact with web servers and perform
various actions on resources.
- The choice of method depends on the nature of the operation the client wants to
perform.
- For example, GET is used for retrieving data, POST for submitting data, PUT for
updating data, and DELETE for removing data.
HttpURLConnection requests in Java

- HttpURLConnection is a class in Java that provides a set of methods to send and


receive data via HTTP.
- It is part of the java.net package and is commonly used for performing HTTP
operations, such as GET, POST, PUT, and DELETE requests.
- HttpURLConnection is a subclass of URLConnection and provides additional
methods specifically for HTTP-related functionality.
- Let us now, send some data to the server that is live on my local machine
HttpURLConnection example
public static void postExample() throws IOException {
URL url = new URL("http://localhost:8080/articles/");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json; utf-8");
connection.setRequestProperty("Accept", "application/json");
connection.setDoOutput(true);

String jsonInput =
"{\"thumbnailUrl\": \"string\", \"title\": \"Hamic\", \"content\": \"Hamigudaa\", \"articleType
\": \"SHORT_ARTICLE\"}";
OutputStream outputStream = connection.getOutputStream();
byte[] input = jsonInput.getBytes("utf-8");
outputStream.write(input, 0, input.length);
System.out.println(connection.getResponseCode());
HttpURLConnection requests in Java explained

- In order to communicate with the server we have to add the headers, that are the
metadata of our actual request specifying the content type of our body and what
we are accepting
- Also the setDoOutput is a method that enables output streams for writing data to
the server.
- Next, we will take our string input and convert it to the byte array that will be
sent to the server as an UTF-8 character encoded string
Sockets

- Sockets are a programming abstraction used for interprocess communication over


a network.
- They provide a standard mechanism for processes on different devices to
communicate with each other.
- Sockets can be thought of as the endpoints in a communication channel, and they
enable data exchange between applications running on different machines.
Sockets cont.

- In Java, the java.net package provides classes and interfaces for working with
sockets. The two main types of sockets in Java are:
- ServerSocket: This class implements a socket that listens for incoming
connections from clients. Once a connection is accepted, a new socket is
created for communication with the client.
- Socket: This class represents a client-side socket that can connect to a
server's socket. It can be used to send and receive data with the server.
Sockets server example

- Let us now implement the Socket server that will accept the remote connections
public static void socketServer(int port) {
try {
ServerSocket serverSocket = new ServerSocket(2345);
while (true) {
Socket connection = serverSocket.accept();
InputStream inputStream = connection.getInputStream();

// Read data from the client


byte[] buffer = new byte[1024];
int bytesRead = inputStream.read(buffer);
String message = new String(buffer, 0, bytesRead);
System.out.println("Received message from client: " + message);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Sockets server example cont.
- In the example shown in the previous slide we are creating the Socket server that
is accepting the connections to itself
- After we accept the connection, by using the InputStream we are taking the the
input stream payload and converting it into the byte array that is then converted
into the String
- So we have created a method that accepts the remote connections and read the
data that has been sent from the client
Sockets client
- Now, let us create a client method that will send the data to server
public static void socketClient(String address, int port) {
try {
Socket connection = new Socket(address, port);
OutputStream outputStream = connection.getOutputStream();

outputStream.write("Hello, Server!".getBytes());

outputStream.close();
connection.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Sockets client explained
- Now, we want to open a Socket connection to the particular ip address and we
will be using the local ip address of the machine in which we are running the
Socket server
- Next we will use the getBytes() method on the String that we want to send to our
server and use the OutputStream to send the payload to the server that
understands the client message
- NOTE: Do not forget to close your Connection and OutputStream after you finish
your work. YOU ARE ALWAYS ACCOUNTABLE FOR MANAGING THE
RESOURCES THAT YOU ARE USING!
Resources
- https://github.com/ibecir/oop-2023
System.out.println("Thanks, bye!");

You might also like