diff --git a/.vscode/launch.json b/.vscode/launch.json index 89515dd..88da375 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,6 +4,13 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { + "type": "java", + "name": "Launch App", + "request": "launch", + "mainClass": "com.scaler.App", + "projectName": "os" + }, { "name": "Python: Current File", "type": "python", @@ -11,7 +18,12 @@ "program": "${file}", "console": "integratedTerminal", "justMyCode": true, - "args": ["-H", "127.0.0.1", "-p", "5001"] + "args": [ + "-H", + "127.0.0.1", + "-p", + "5001" + ] } ] } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index de288e1..f438951 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "python.formatting.provider": "black" + "python.formatting.provider": "black", + "java.configuration.updateBuildConfiguration": "interactive" } \ No newline at end of file diff --git a/os/code/os/src/main/java/com/scaler/App.java b/os/code/os/src/main/java/com/scaler/App.java index c5143e6..46a6835 100644 --- a/os/code/os/src/main/java/com/scaler/App.java +++ b/os/code/os/src/main/java/com/scaler/App.java @@ -1,23 +1,28 @@ package com.scaler; +import com.scaler.threads.Printer; + /** * Hello world! * */ public class App { - public static void print() { - System.out.println("Hello World! printed by: " + Thread.currentThread().getName()); - } - public static void main(String[] args) { - - print(); - + System.out.println("Hello world. Printed by :" + Thread.currentThread().getName()); for (int i = 0; i < 10; i++) { - TextPrinter textPrinter = new TextPrinter(String.valueOf(i)); - Thread thread = new Thread(textPrinter); + Printer printer = new Printer(String.valueOf(i)); + Thread thread = new Thread(printer); thread.start(); } } } + +// Print number 1 to 10 on a single thread +// Print number 1 to 10 each on different threads +// 1 - Thread 1 +// 2 - Thread 2 +// ... +// 10 Thread 10 + +// \ No newline at end of file diff --git a/os/code/os/src/main/java/com/scaler/scheduling/FirstComeFirstServe.java b/os/code/os/src/main/java/com/scaler/scheduling/FirstComeFirstServe.java index f65a1ec..3f252f4 100644 --- a/os/code/os/src/main/java/com/scaler/scheduling/FirstComeFirstServe.java +++ b/os/code/os/src/main/java/com/scaler/scheduling/FirstComeFirstServe.java @@ -50,4 +50,11 @@ public class FirstComeFirstServe { } return queue; } -} \ No newline at end of file +} + +// Side-assignment +// Implement tie breaking in scheduling +// If two processes have the same arrival time +// * Check the id +// * Also, you can check the burst time +// One line code \ No newline at end of file diff --git a/os/code/os/src/main/java/com/scaler/scheduling/models/IncomingProcess.java b/os/code/os/src/main/java/com/scaler/scheduling/models/IncomingProcess.java index ef2d5ae..064d25a 100644 --- a/os/code/os/src/main/java/com/scaler/scheduling/models/IncomingProcess.java +++ b/os/code/os/src/main/java/com/scaler/scheduling/models/IncomingProcess.java @@ -8,7 +8,7 @@ import lombok.Setter; public class IncomingProcess { private int id; private int arrivalTime; - private int burstTime; + private int burstTime; // How long the process will take to complete private int completedAt; @@ -18,3 +18,5 @@ public class IncomingProcess { this.burstTime = burstTime; } } + +// List schedule(List) diff --git a/os/code/os/src/main/java/com/scaler/threads/Printer.java b/os/code/os/src/main/java/com/scaler/threads/Printer.java new file mode 100644 index 0000000..946437f --- /dev/null +++ b/os/code/os/src/main/java/com/scaler/threads/Printer.java @@ -0,0 +1,14 @@ +package com.scaler.threads; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public class Printer implements Runnable { + + private String text; + + @Override + public void run() { + System.out.println(text + " Printed by " + Thread.currentThread().getName()); + } +} diff --git a/os/code/os/target/classes/com/scaler/App.class b/os/code/os/target/classes/com/scaler/App.class index 6737821..259cdd5 100644 Binary files a/os/code/os/target/classes/com/scaler/App.class and b/os/code/os/target/classes/com/scaler/App.class differ diff --git a/os/notes/02-round-robin-threads-hw.pdf b/os/notes/02-round-robin-threads-hw.pdf new file mode 100644 index 0000000..1b592af Binary files /dev/null and b/os/notes/02-round-robin-threads-hw.pdf differ diff --git a/os/notes/02-round-robin-threads.pdf b/os/notes/02-round-robin-threads.pdf new file mode 100644 index 0000000..95096a7 Binary files /dev/null and b/os/notes/02-round-robin-threads.pdf differ diff --git a/os/notes/03-threads-synchronisation.md b/os/notes/03-threads-synchronisation.md new file mode 100644 index 0000000..bcfc1e7 --- /dev/null +++ b/os/notes/03-threads-synchronisation.md @@ -0,0 +1,75 @@ +# Threads and Synchronisation + +## Executor + +The `Executor` interface is used to execute tasks. It is a generic interface that can be used to execute any kind of task. The `Executor` interface has only one method: + +```java +public interface Executor { + void execute(Runnable command); +} +``` + +The `execute` method takes a `Runnable` object as a parameter. The `Runnable` interface is a functional interface that has only one method. Executors internally use a thread pool to execute the tasks. The `execute` method is non-blocking. It returns immediately after submitting the task to the thread pool. The `execute` method is used to execute tasks that do not return a result. + +A thread pool is a collection of threads that are used to execute tasks. +Instead of creating a new thread for each task, a thread pool reuses the existing threads to execute the tasks. This improves the performance of the application. + +The `Executor` interface has a method called `newCachedThreadPool` that returns an `ExecutorService` object. The `ExecutorService` interface extends the `Executor` interface. The `ExecutorService` interface has methods to execute tasks that return a result. The `ExecutorService` interface also has methods to shutdown the thread pool. + +To run a task using the `Executor` interface, we can use the `newCachedThreadPool` method to create an `ExecutorService` object. The `newCachedThreadPool` method returns an `ExecutorService` object that uses a thread pool with a variable number of threads. The `newCachedThreadPool` method creates a new thread for each task if there are no idle threads in the thread pool. If there is an idle thread in the thread pool, the `newCachedThreadPool` method reuses the idle thread to execute the task. The `newCachedThreadPool` method returns an `ExecutorService` object that uses a thread pool with a variable number of threads. + +```java +Executor executorService = Executors.newCachedThreadPool(); +executorService.execute(() -> System.out.println("Hello World")); +``` + +## Callable and Future + +Runnables do not return a result. If we want to execute a task that returns a result, we can use the `Callable` interface. The `Callable` interface is a functional interface that has only one method: + +```java +public interface Callable { + V call() throws Exception; +} +``` + +The `call` method returns a result of type `V`. The `call` method can throw an exception. The `Callable` interface is used to execute tasks that return a result. +For instance we can use the `Callable` interface to execute a task that returns the sum of two numbers: + +```java +Callable sumTask = () -> 2 + 3; +``` + +In order to execute a task that returns a result, we can use the `submit` method of the `ExecutorService` interface. The `submit` method takes a `Callable` object as a parameter. The `submit` method returns a `Future` object. The `Future` interface has a method called `get` that returns the result of the task. The `get` method is a blocking method. It waits until the task is completed and then returns the result of the task. + +```java +ExecutorService executorService = Executors.newCachedThreadPool(); +Future future = executorService.submit(() -> 2 + 3); +Integer result = future.get(); +``` + +Futures can be used to cancel tasks. The `Future` interface has a method called `cancel` that can be used to cancel a task. The `cancel` method takes a boolean parameter. If the boolean parameter is `true`, the task is cancelled even if the task is already running. If the boolean parameter is `false`, the task is cancelled only if the task is not running. + +```java +ExecutorService executorService = Executors.newCachedThreadPool(); +Future future = executorService.submit(() -> 2 + 3); +future.cancel(false); +``` + +## Synchronisation + +Whenever we have multiple threads that access the same resource, we need to make sure that the threads do not interfere with each other. This is called synchronisation. + +Synchronisation can be seen in the adder and subtractor example. The adder and subtractor threads access the same counter variable. If the adder and subtractor threads do not synchronise, the counter variable can be in an inconsistent state. + +* Create a count class that has a count variable. +* Create two different classes `Adder` and `Subtractor`. +* Accept a count object in the constructor of both the classes. +* In `Adder`, iterate from 1 to 100 and increment the count variable by 1 on each iteration. +* In `Subtractor`, iterate from 1 to 100 and decrement the count variable by 1 on each iteration. +* Print the final value of the count variable. +* What would the ideal value of the count variable be? +* What is the actual value of the count variable? +* Try to add some delay in the `Adder` and `Subtractor` classes using inspiration from the code below. What is the value of the count variable now? +