Download as pdf or txt
Download as pdf or txt
You are on page 1of 35

Page |1

Addis Ababa University


Addis Ababa Institute of Technology
School of Information technology and scientific
computing

Operating System

Prepared By
Name ID section
MOTI HATEW ATR/3469/10 3
Henok Adane ATR/3109/10 3
Hawltu Yenealem ATR/9258/10 1
Natnael Awol ATR/3701/09 1

Submitted to: Dr. Henock Mulugeta (Phd)

February, 2021
Page |2

Project Name page Number

Scheduling Algorithm 2

Chat Room 19

Dining philosophy 28

Scheduling Algorithm

Contents

Introduction/Purpose........................................................................................................3

Materials/Components and Equipment……………………………………………….….........6

Methods/Procedure...........................................................................................................6

FCFS class code ................................................................................................................6

SJF class code……………………………………………………………………………………7

SJF Preemptive code……………………………………………………………………………..8

Priority code……………………………………………………………………………...............9

Round robin code………………………………………………………………………………....9

Scheduling Algorithm code………………………………………………………………………11

Output...............................................................................................................................3

Conclusion…………………………………………………………………………….................16

References.........................................................................................................................16

2
Page |3

Introduction/Purpose

CPU Scheduling is a process of determining which process will own CPU for execution while
another process is on hold. The main task of CPU scheduling is to make sure that whenever
the CPU remains idle, the OS at least select one of the processes available in the ready queue
for execution. The selection process will be carried out by the CPU scheduler. It selects one of
the processes in memory that are ready for execution.

Types of CPU Scheduling

Here are two kinds of Scheduling methods:

1. Preemptive Scheduling

In Preemptive Scheduling, the tasks are mostly assigned with their priorities. Sometimes it is
important to run a task with a higher priority before another lower priority task, even if the
lower priority task is still running. The lower priority task holds for some time and resumes
when the higher priority task finishes its execution.

2. Non-Preemptive Scheduling

In this type of scheduling method, the CPU has been allocated to a specific process. The
process that keeps the CPU busy will release the CPU either by switching context or
terminating. It is the only method that can be used for various hardware platforms. That's
because it doesn't need special hardware (for example, a timer) like preemptive scheduling.

Types of CPU scheduling Algorithm

There are mainly six types of process scheduling algorithms

1. First Come First Serve (FCFS)


2. Shortest-Job-First (SJF) Scheduling
3. Shortest Remaining Time
4. Priority Scheduling
5. Round Robin Scheduling

First Come First Serve (FCFS): Simplest scheduling algorithm


that schedules according to arrival times of processes.
First come first serve scheduling algorithm states that
the process that requests the CPU first is allocated the
CPU first. It is implemented by using the FIFO queue.
3
Page |4

When a process enters the ready queue, its PCB is


linked onto the tail of the queue. When the CPU is
free, it is allocated to the process at the head of the
queue. The running process is then removed from the
queue. FCFS is a non-preemptive scheduling
algorithm.

Shortest Job First (SJF): Process which have the shortest burst time
are scheduled first. If two processes have the same bust time then FCFS is
used to break the tie. It is a non-preemptive scheduling algorithm.

Shortest Remaining Time: Shortest remaining time (SRT) is the


preemptive version of the SJN algorithm. The processor is allocated to the
job closest to completion but it can be preempted by a newer ready job
with shorter time to completion .Impossible to implement in interactive
systems where required CPU time is not known. It is often used in batch
environments where short jobs need to give preference.

Priority Based Scheduling: Priority scheduling is a method of


scheduling processes based on priority. In this method, the scheduler selects
the tasks to work as per the priority. Priority scheduling also helps OS to
involve priority assignments. The processes with higher priority should be
carried out first, whereas jobs with equal priorities are carried out on a
round-robin or FCFS basis. Priority can be decided based on memory
requirements, time requirements, etc.

Round-Robin Scheduling: Round robin is the oldest, simplest


scheduling algorithm. The name of this algorithm comes from the round-
robin principle, where each person gets an equal share of something in turn.
It is mostly used for scheduling algorithms in multitasking. This algorithm
method helps for starvation free execution of processes.

4
Page |5

Materials/Components and
Equipment
➢ Java IDLE
➢ Java: JDK

Procedures

We use the 5 scheduling algorithms uses for scheduling purpose.


For each algorithm:
i. Choose the type of algorithm to use from the listed algorithms
ii. Enter the number of process to be schedule
iii. Enter the id for the process created
iv. Then enter the arrival time for the specific process
v. Enter the burst time for that process
vi. Continues until all the process are creates
vii. Finally the algorithm will schedule based on the selected algorithm

Code for each algorithm

1. First come First Served (FCFS)


package com.company;

import java.util.List;

// 1 FCSC First come first serve Scheduling Algorithm


public class FCSC extends SchedulingAlgorithms {
public FCSC(String algoType) {
super(algoType);
}

void run() {
List<Process> processes = getInput();
System.out.println("Order in which processes gets executed \n");
for (int i = 0; i < processes.size(); i++)
System.out.print(processes.get(i).processID + " ");
findavgTime(processes, processes.size());
}
}

2. shortest Job first(SJF) scheduling


package com.company;

import java.util.Collections;
import java.util.List;

5
Page |6

public class ShortestJobFirst extends SchedulingAlgorithms {


// 2 Short Job First Algorithm
public ShortestJobFirst(String algoType) {
super(algoType);
}

List<Process> sortProcesses(List<Process> proc) {


if (checkSameArrival(proc)) {
Collections.sort(proc, new Process.BurstComparator());
return proc;
}
Collections.sort(proc, new Process.ArrivalComparator());
Process firstProcess = proc.get(0);

List<Process> newProcesses = proc.subList(1, proc.size());

Collections.sort(newProcesses, new Process.BurstComparator());


newProcesses.add(0, firstProcess);
return newProcesses;
}

// which checks for the processes arrival time if all comes at once
boolean checkSameArrival(List<Process> proc) {
boolean isSame = false;
for (int i = 0; i < proc.size(); i++) {
if (proc.get(i).arrivalTime == 0) {
isSame = true;
} else {
isSame = false;
}
}
return isSame;
}

void run() {
List<Process> processes = sortProcesses(getInput());
System.out.println("Order in which processes gets executed \n");
for (int i = 0; i < processes.size(); i++) {
System.out.print(processes.get(i).processID + " ");
}
findavgTime(processes, processes.size());
}
}

3. preemptive shortest job first


package com.company;

import java.util.List;

// 3 Preemptive CPU Scheduling Algorithm


public class PreemptiveSJF extends SchedulingAlgorithms {

6
Page |7

public PreemptiveSJF(String algoType) {


super(algoType);
}

@Override
void findWaitingTime(List<Process> proc, int n, int wt[]) {
int rem_time[] = new int[n];

// Copy the burst time into rem_time[]


for (int i = 0; i < n; i++) {
rem_time[i] = proc.get(i).burstTime;
}
int complete = 0, clock_time = 0, minm = Integer.MAX_VALUE;
int sj = 0, finish_time;
boolean check = false;

while (complete != n) {
for (int j = 0; j < n; j++) {
if ((proc.get(j).arrivalTime <= clock_time) && (rem_time[j] <
minm) && rem_time[j] > 0) {
minm = rem_time[j];
sj = j;
check = true;
}
}
if (!check) {
clock_time++;
continue;
}
rem_time[sj]--;
// Update minimum
minm = rem_time[sj];
if (minm == 0)
minm = Integer.MAX_VALUE;

if (rem_time[sj] == 0) {
complete++;
check = false;
finish_time = clock_time + 1;
wt[sj] = finish_time - proc.get(sj).burstTime -
proc.get(sj).arrivalTime;
if (wt[sj] < 0) {
wt[sj] = 0;
}
}
clock_time++;
}
}

void run() {
List<Process> processes = getInput();
System.out.println("Order in which processes gets executed \n");
for (int i = 0; i < processes.size(); i++)
System.out.print(processes.get(i).processID + " ");
findavgTime(processes, processes.size());
}
}

7
Page |8

4. Priority Scheduling
package com.company;

import java.util.List;

// 4 Priority CPU Scheduling Algorithm


public class Priority extends SchedulingAlgorithms {
public Priority(String algoType) {
super(algoType);
}

void run() {
List<Process> processes = getInput();
processes.sort(new Process.PriorityComparator());
System.out.println("Order in which processes gets executed ");
for (int i = 0; i < processes.size(); i++)
System.out.print(processes.get(i).processID + " ");
findavgTime(processes, processes.size());
}
}

5. Round robin Scheduling


package com.company;

import java.util.List;
import java.util.Scanner;

import static com.company.Main.checkValidInputAndGetValue;

// 5 Round Robin CPU Scheduling Algorithm


public class RoundRobin extends SchedulingAlgorithms {
public RoundRobin(String algoType) {
super(algoType);
}

// @Override
void findWaitingTime(List<Process> proc, int n, int quantum, int
completion_time[]) {
int rem_time[] = new int[n];
for (int i = 0; i < n; i++) {
rem_time[i] = proc.get(i).burstTime;
}
int t = 0;
int clock_counter = 0;
while (true) {
boolean done = true;
for (int i = 0; i < n; i++) {
if (rem_time[i] > 0) {
done = false;
if (rem_time[i] > quantum && proc.get(i).arrivalTime <=
clock_counter) {
8
Page |9

t += quantum;
rem_time[i] -= quantum;
clock_counter++;
} else {
if (proc.get(i).arrivalTime <= clock_counter) {
t += rem_time[i];
rem_time[i] = 0;
completion_time[i] = t;
clock_counter++;
}
}
}
}
if (done) {
break;
}
}
}

@Override
void findTurnAroundTime(List<Process> proc, int n, int wt[], int tat[], int
completion_time[]) {
for (int i = 0; i < n; i++) {
tat[i] = completion_time[i] - proc.get(i).arrivalTime;
wt[i] = tat[i] - proc.get(i).burstTime;
}
}

void findAvgTime(List<Process> proc, int n, int quantum) {


int wt[] = new int[n];
int tat[] = new int[n];
int total_wt = 0, total_tat = 0;

int completion_time[] = new int[n];


findWaitingTime(proc, n, quantum, completion_time);
findTurnAroundTime(proc, n, wt, tat, completion_time);
display(proc, proc.size(), wt, tat, total_wt, total_tat,
completion_time);
}

void run() {
Scanner sc = new Scanner(System.in);
int quantum;
System.out.println("Enter Quantum Number: ");
quantum = checkValidInputAndGetValue(sc);
List<Process> processes = getInput();

System.out.println("Order in which processes gets executed \n");


for (int i = 0; i < processes.size(); i++)
System.out.print(processes.get(i).processID + " ");
findAvgTime(processes, processes.size(), quantum);
}
}

9
P a g e | 10

6. Scheduling algorithm
package com.company;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import static com.company.Main.checkValidInputAndGetValue;

// parent class for all scheduling algorithm that share same process
public class SchedulingAlgorithms {
public String algoType;
public String InputText;

public SchedulingAlgorithms(String algoType) {


this.algoType = algoType;
InputText = algoType.equalsIgnoreCase("Priority") ? "Priority" :
"Arrival Time";
System.out.println("\nYou have selected "+ algoType + " Algorithm \n");
}

void findWaitingTime(List<Process> proc, int n, int wt[]) {


int currentTime = 0;
for (int i = 0; i < n; i++) {
// check for if algorithm prioirty or other
if (algoType.equalsIgnoreCase("Priority")) {
wt[i] = currentTime;
} else {
wt[i] = currentTime - proc.get(i).arrivalTime;
}
currentTime = currentTime + proc.get(i).burstTime;
}
wt[0] = 0;
}

void findTurnAroundTime(List<Process> proc, int n, int wt[], int tat[], int


compl_time[]) {
for (int i = 0; i < n; i++) {
tat[i] = proc.get(i).burstTime + wt[i];
if (algoType.equalsIgnoreCase("Priority")) {
compl_time[i] = tat[i];
} else {
compl_time[i] = tat[i] + proc.get(i).arrivalTime;
}
// total_tat = total_tat + tat[i];
}
}

void display(List<Process> proc, int n, int wt[], int tat[], int total_wt,
int total_tat, int compl_time[]) {
System.out.println("\n");

System.out.println("===========================================================
=================================================== ");
System.out.println("Processes ID\t" + InputText + "\t " + "Burst
time\t" + "Waiting time\t" + "Turn Around Time\t" + "completion time\t");
10
P a g e | 11

System.out.println("===========================================================
=================================================== ");

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


total_wt = total_wt + wt[i];
total_tat = total_tat + tat[i];

System.out.println("\t"+ proc.get(i).processID + "\t\t\t\t" +


proc.get(i).arrivalTime + "\t\t\t\t" + proc.get(i).burstTime + "\t\t\t\t"
+ wt[i] + "\t\t\t\t"
+ tat[i] + "\t\t\t\t" + compl_time[i]);
}

System.out.print("\nAverage waiting time = " + (float) total_wt /


(float) n);
System.out.print("\nAverage turn around time = " + (float) total_tat /
(float) n);

// find waiting time and turnaround time for each process and also total
void findavgTime(List<Process> proc, int n) {
int wt[] = new int[n], tat[] = new int[n], compl_time[] = new int[n];
int total_wt = 0, total_tat = 0;
findWaitingTime(proc, n, wt);
findTurnAroundTime(proc, n, wt, tat, compl_time);
display(proc, n, wt, tat, total_wt, total_tat, compl_time);
}
// get first input
List<Process> getInput() {
Scanner sc = new Scanner(System.in);
System.out.println("Enter Number of Process...");
int numberOfProcess = checkValidInputAndGetValue(sc);
int pId, aT, bT;
List<Process> processes = new ArrayList<>();
for (int i = 0; i < numberOfProcess; i++) {
System.out.println("...Process " + (i + 1) + "...");
System.out.println("Enter Process Id: ");
pId = checkValidInputAndGetValue(sc);
System.out.println("Enter " + InputText + ": ");
aT = checkValidInputAndGetValue(sc);
System.out.println("Enter Burst Time: ");
bT = checkValidInputAndGetValue(sc);
Process process = new Process(pId, bT, aT, algoType);
processes.add(process);
}

return processes;
}
}

11
P a g e | 12

7. Main Class
package com.company;

import java.util.Scanner;

public class Main {

public static void main(String[] agrs) {


run();
}

static int checkValidInputAndGetValue(Scanner sc){


int value = 0;
try {
value = sc.nextInt();
} catch(Exception e){
System.out.println("INVALID INPUT! Enter a number only!");
sc = new Scanner(System.in);
value = checkValidInputAndGetValue(sc);
return value;
}
return value;
}
static void run() {
boolean stop = false;
while (!stop) {
displayMenu();
Scanner sc = new Scanner(System.in);
int choice = checkValidInputAndGetValue(sc);
stop = choice == 0;
if (stop) {
break;
}
switch (choice) {
case 1: {
FCSC fcsc = new FCSC("FCSC");
fcsc.run();
System.out.println("\n\nEnter 1 To Rerun FCSC\tEnter 2 To
Main Menu\tPress Any Other Key To Exit");
choice = checkValidInputAndGetValue(sc);
if (choice == 1) {
fcsc.run();
} else if (choice == 2) {
break;
} else {
stop = true;
}
break;
}
case 2: {
ShortestJobFirst sjf = new ShortestJobFirst("SJF.javaa");
sjf.run();
System.out.println("\n\nEnter 1 To Rerun SJF.javaa\tEnter 2
To Main Menu\tPress Any Other Key To Exit");
choice = checkValidInputAndGetValue(sc);
if (choice == 1) {
sjf.run();
12
P a g e | 13

} else if (choice == 2) {
break;
} else {
stop = true;
}
break;
}
case 3: {
PreemptiveSJF preemptiveSJF = new
PreemptiveSJF("PreemptiveSJF");
preemptiveSJF.run();
System.out.println("\n\nEnter 1 To Rerun
PreemptiveSJF\tEnter 2 To Main Menu\tPress Any Other Key To Exit");
choice = checkValidInputAndGetValue(sc);
if (choice == 1) {
preemptiveSJF.run();
} else if (choice == 2) {
break;
} else {
stop = true;
}
break;
}
case 4: {
Priority priority = new Priority("Priority");
priority.run();
System.out.println("\n\nEnter 1 To Rerun Priority\tEnter 2
To Main Menu\tPress Any Other Key To Exit");
choice = checkValidInputAndGetValue(sc);
if (choice == 1) {
priority.run();
} else if (choice == 2) {
break;
} else {
stop = true;
}
break;
}
case 5: {
RoundRobin roundRobin = new RoundRobin("RoundRobin");
roundRobin.run();
System.out.println("\n\nEnter 1 To Rerun RoundRobin\tEnter
2 To Main Menu\tPress Any Other Key To Exit");
choice = checkValidInputAndGetValue(sc);
if (choice == 1) {
roundRobin.run();
} else if (choice == 2) {
break;
} else {
stop = true;
}
break;
}
default: {
break;
}
}
}
13
P a g e | 14

static void displayMenu() {


System.out.println("\n");
System.out.println("============================================ ");
System.out.println("Welcome to CPU Process Scheduling Algorithms");
System.out.println("============================================ ");
System.out.println("Enter 1 FCSC(First Come First Serve Algorithm");
System.out.println("Enter 2 Non Preemptive SJF.javaa(Shortest Job First
Algorithm");
System.out.println("Enter 3 Preemptive SJF.javaa(Shortest Job First
Algorithm");
System.out.println("Enter 4 Priority Scheduling Algorithm");
System.out.println("Enter 5 Round Robin Scheduling Algorithm");
System.out.println("Enter 0 To Exit");
System.out.println("============================================ ");
}

The output from the console are listed below


Welcome Console

1. FCFS

14
P a g e | 15

2. SJF

15
P a g e | 16

3. Preemptive SJF

16
P a g e | 17

4. Priority

5. Round-Robin

17
P a g e | 18

Conclusions

• We tried to cover the most used CPU scheduling algorithms.


CPU scheduling is a process of determining which process will own CPU for
execution while another process is on hold.
• In Preemptive Scheduling, the tasks are mostly assigned with their priorities.
• In the Non-preemptive scheduling method, the CPU has been allocated to a
specific process.
• Burst time is a time required for the process to complete execution. It is also
called running time.
• CPU utilization is the main task in which the operating system needs to make
sure that CPU remains as busy as possible
• The number of processes that finish their execution per unit time is known
Throughput.

References

➢ Lecture Notes on process and threads , Henock Mulugeta (PhD)


➢ Google
➢ Tutorial point (https://www.tutorialspoint.com)

18
P a g e | 19

Client Server Char room

Contents

Introduction/Purpose.....................................................................................................20

Materials/Components and Equipment…………………………………............................20

Methods/Procedure........................................................................................................21

Server class code .............................................................................................................21

Client class code……………………………………………………………………………….23

Output.............................................................................................................................25

Conclusion……………………………………………………………………………................27

References........................................................................................................................27

19
P a g e | 20

Introduction
Networking is a major branch of programming that is vital to connecting users through
devices. As such many programming languages have multiple ways to form connections users
and servers or between peers. For starting out programming, Java is one of the first languages
many programmers learn, and one of the interesting ways java can handle network
connections is through the use of Java Sockets.
We have prepared this tutorial to instruct how to use sockets in java by developing a chat
server between one server and many users.
This documentation is divided between client side and server side development.

Materials/Components and Equipment


➢ Java IDE

➢ Java JDK

➢ packages

20
P a g e | 21

Methods/Procedure
We use the following steps to make multithreading chat room on client and Server side.

1. Setup a Server Socket in the Server Class


2. Step 2: Create a Socket in the Login Class
3. Create a Loop to Continuously Accept Client
4. Create the Client Threads
5. Create the Server Thread
6. Make the Client Thread Send and Receive Data
7. Make the Server Thread Send and Receive Data
8. Test the Server and Add Optional Functionality

Server chat class


import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Set;
import java.util.HashSet;
import java.util.Scanner;
import java.util.concurrent.Executors;

public class ChatServer {

// All client names, so we can check for duplicates upon registration.


private static Set<String> names = new HashSet<>();

// The set of all the print writers for all the clients, used for
broadcast.
private static Set<PrintWriter> writers = new HashSet<>();

public static void main(String[] args) throws Exception {


System.out.println("The chat server is running...");
var pool = Executors.newFixedThreadPool(100);
try (var listener = new ServerSocket(8989)) {
while (true) {
pool.execute(new Handler(listener.accept()));
}
}
}

/**
21
P a g e | 22

* The client handler task.


*/
private static class Handler implements Runnable {
private String name;
private Socket socket;
private Scanner in;
private PrintWriter out;

public Handler(Socket socket) {


this.socket = socket;
}

/**
* Services this thread's client by repeatedly requesting a screen name
until a
* unique one has been submitted
*/
public void run() {
try {
in = new Scanner(socket.getInputStream());
out = new PrintWriter(socket.getOutputStream(), true);

// Keep requesting a name until we get a unique one.


while (true) {
out.println("SUBMITNAME");
name = in.nextLine();
if (name == null) {
return;
}
synchronized (names) {
if (!name.isBlank() && !names.contains(name)) {
names.add(name);
break;
}
}
}

out.println("NAMEACCEPTED " + name);


for (PrintWriter writer : writers) {
writer.println("MESSAGE " + name + " has joined");
}
writers.add(out);

// Accept messages from this client and broadcast them.


while (true) {
String input = in.nextLine();
if (input.toLowerCase().startsWith("/quit")) {
return;
}
for (PrintWriter writer : writers) {

writer.println("MESSAGE " + name + ": " + input);


}
}
} catch (Exception e) {
System.out.println(e);
} finally {
if (out != null) {
22
P a g e | 23

writers.remove(out);
}
if (name != null) {
System.out.println(name + " is leaving");
names.remove(name);
for (PrintWriter writer : writers) {
writer.println("MESSAGE " + name + " has left");
}
}
try {
socket.close();
} catch (IOException e) {
}
}
}
}
}

2 Client chat class


3 import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class ChatClient {

String serverAddress;
Scanner in;
PrintWriter out;
JFrame frame = new JFrame("Chat Room");
JTextField textField = new JTextField(50);
JTextArea messageArea = new JTextArea(16, 50);
// we have used port number 8989

public ChatClient(String serverAddress) {


this.serverAddress = serverAddress;

textField.setEditable(false);
messageArea.setEditable(false);
frame.getContentPane().add(textField, BorderLayout.SOUTH);
frame.getContentPane().add(new JScrollPane(messageArea),
BorderLayout.CENTER);
frame.pack();

// Send on enter then clear to prepare for next message


textField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
out.println(textField.getText());
23
P a g e | 24

textField.setText("");
}
});
}

private String getName() {


return JOptionPane.showInputDialog(frame, "Enter your name:",
"Login",
JOptionPane.PLAIN_MESSAGE);
}

private void run() throws IOException {


try {
var socket = new Socket(serverAddress, 8989);
in = new Scanner(socket.getInputStream());
out = new PrintWriter(socket.getOutputStream(), true);

while (in.hasNextLine()) {
var line = in.nextLine();
if (line.startsWith("SUBMITNAME")) {
out.println(getName());
} else if (line.startsWith("NAMEACCEPTED")) {
this.frame.setTitle("Chatter - " +
line.substring(13));
textField.setEditable(true);
} else if (line.startsWith("MESSAGE")) {
messageArea.append(line.substring(8) + "\n");
}
}
}catch (Exception e) {
System.out.println("There is no Server running!");
}

finally {
frame.setVisible(false);
frame.dispose();
}
}

public static void main(String[] args) throws Exception {


// we have used localhost as a server with portnumber 8989
var client = new ChatClient("127.0.0.1");
client.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
client.frame.setVisible(true);
client.run();
}
}

The Sample output from chat room are

24
P a g e | 25

Entering in to client class

More than one clients are entering into the chat

25
P a g e | 26

User 1 and user 2 left the chat the other will be notified

Only user 1 has left the chat

Conclusion
26
P a g e | 27

From this java project assignment, we have seen how to implement multithreading client sever
application in java programming on chat between process server and client. Using of threads
for having more than one clients served by one server.

Advantages from java multithreading


1) It doesn't block the user because threads are independent and you can perform multiple
operations at the same time.

2) You can perform many operations together, so it saves time.

3) Threads are independent, so it doesn't affect other threads if an exception occurs in a single
thread.

References
➢ Lecture notes , Henock Mulugeta (PhD)
➢ Google
➢ Tutorial point (https://www.tutorialspoint.com)

27
P a g e | 28

The Dining Philosophers Problem in Java

Contents

Introduction/Purpose.....................................................................................................29

Problem …………………………………………………..…………………………………….29

Solution.........................................................................................................................29

Implementation .............................................................................................................30

Probem with solution …………………………………………………………………………33

Resolving deadlock.........................................................................................................33

References......................................................................................................................35

6. 1. Introduction
The Dining Philosophers problem is one of the classic problems used to describe
synchronization issues in a multi-threaded environment and illustrate techniques for solving
them. Dijkstra first formulated this problem and presented it regarding computers accessing
tape drive peripherals.

28
P a g e | 29

The present formulation was given by Tony Hoare, who is also known for inventing the
quicksort sorting algorithm. In this article, we analyze this well-known problem and code a
popular solution.

7. 2. The Problem

The diagram above represents the problem. There are five silent philosophers (P1 – P5) sitting
around a circular table, spending their lives eating and thinking.
There are five forks for them to share (1 – 5) and to be able to eat, a philosopher needs to have
forks in both his hands. After eating, he puts both of them down and then they can be picked
by another philosopher who repeats the same cycle.

The goal is to come up with a scheme/protocol that helps the philosophers achieve their goal

of eating and thinking without getting starved to death.

8. 3. A Solution
An initial solution would be to make each of the philosophers follow the following protocol:

29
P a g e | 30

As the above pseudo code describes, each philosopher is initially thinking. After a certain
amount of time, the philosopher gets hungry and wishes to eat.
At this point, he reaches for the forks on his either side and once he's got both of them,
proceeds to eat. Once the eating is done, the philosopher then puts the forks down, so that
they're available for his neighbor.

9. 4. Implementation
We model each of our philosophers as classes that implement the Runnable interface so that we
can run them as separate threads. Each Philosopher has access to two forks on his left and right
sides:

We also have a method that instructs a Philosopher to perform an action – eat, think, or acquire
forks in preparation for eating:

30
P a g e | 31

As shown in the code above, each action is simulated by suspending the invoking thread for a
random amount of time, so that the execution order isn't enforced by time alone.
Now, let's implement the core logic of a Philosopher.
To simulate acquiring a fork, we need to lock it so that no two Philosopher threads acquire it at
the same time.
To achieve this, we use the synchronized keyword to acquire the internal monitor of the fork
object and prevent other threads from doing the same. We proceed with implementing
the run() method in the Philosopher class now:

31
P a g e | 32

This scheme exactly implements the one described earlier: a Philosopher thinks for a while and
then decides to eat.
After this, he acquires the forks to his left and right and starts eating. When done, he places the
forks down. We also add timestamps to each action, which would help us understand the
order in which events occur.
To kick start the whole process, we write a client that creates 5 Philosophers as threads and
starts all of them:

We model each of the forks as generic Java objects and make as many of them as there are
philosophers. We pass each Philosopher his left and right forks that he attempts to lock using
the synchronized keyword.
Running this code results in an output similar to the following. Your output will most likely
differ from the one given below, mostly because the sleep() method is invoked for a different
interval:

32
P a g e | 33

All the Philosophers initially start off thinking, and we see that Philosopher 1 proceeds to pick up
the left and right fork, then eats and proceeds to place both of them down, after which
`Philosopher 5` picks it up.

10. 5. The Problem with the Solution: Deadlock


Though it seems that the above solution is correct, there's an issue of a deadlock arising.

A deadlock is a situation where the progress of a system is halted as each process is waiting to

acquire a resource held by some other process.


We can confirm the same by running the above code a few times and checking that
sometimes, the code just hangs. Here's a sample output that demonstrates the above issue:

In this situation, each of the Philosophers has acquired his left fork, but can't acquire his right
fork, because his neighbor has already acquired it. This situation is commonly known as
the circular wait and is one of the conditions that results in a deadlock and prevents the
progress of the system.

1. 6. Resolving the Deadlock


As we saw above, the primary reason for a deadlock is the circular wait condition where each
process waits upon a resource that's being held by some other process. Hence, to avoid a
33
P a g e | 34

deadlock situation we need to make sure that the circular wait condition is broken. There are
several ways to achieve this, the simplest one being the follows:
All Philosophers reach for their left fork first, except one who first reaches for his right fork.
We implement this in our existing code by making a relatively minor change in code:

The change comes in lines 17-19 of the above code, where we introduce the condition that
makes the last philosopher reach for his right fork first, instead of the left. This breaks the
circular wait condition and we can avert the deadlock.
Following output shows one of the cases where all the Philosophers get their chance to think
and eat, without causing a deadlock:

34
P a g e | 35

It can be verified by running the code several times that the system is free from the deadlock
situation that occurred before.

References
➢ Lecture notes , Henock Mulugeta (PhD)
➢ Google
➢ Tutorial point (https://www.tutorialspoint.com)

35

You might also like