Multi-threading in
java is considered as a complex piece to understand. In this article, I am
trying to explain multi-threading implementation with some live examples. Intention
behind this is to first sense the requirement of any operation/method and then
the usages of it.
However, given
analogy may not exactly fit the use case but still I hope we can bear with it
for sake of understanding. So please bear with me.
I would like to
take instance of very usual work flow over any usual food joint where tasks are
divided among various group of people like shef will cook or prepare the food
item, some people got responsibility to package the order and some manage the counter
who interact with customer and forward the order for fulfilment. Another actor I
can foresee is Customer. I would like to name this food joint as Bollywood food
point and here is the behavior of store that I would like to simulate
-
In my
store, there are 3 shefs (Sharukh, Salman and Amir), 1 packager (Vivek) and two
counter managers (Alia, Shraddha and Pari). When a store opens, all of them are
available for service and waiting for order to get placed.
-
Whenever
a customer visits the store the activities followed are-
o
Customer
aligned to one of the counter person
o
Counter
person greet customer and ask for order
o
An order
number is saved against this transaction
o
Customer
place the order
o
Counter
person calculate the bill and notify customer
o
Customer
pays bill and wait for order
o
Counter
person sends the order for fulfillment
o
Shef
prepare the order. If order has multiple items, multiple shef prepare it
o
Once order
is done, it is packaged by packager
o
System
monitor shows the fulfilled order number
o
Customer
receives the order.
In above example, the entire processing is done in single
container i.e. your joint. This can be simulated as a
process. Like a store, process is an executable
which performs a set of action and has all the
required dedicated resources
like memory etc.
Each action in above example which can process independently can be assumed as Thread. A thread is sequence of action
under a process which can be independently executed. Its periphery remains
within the process and can share data among themselves as well as with process.
To start with, let’s
simulate this for one customer (Sachin) to remain it simple. Sachin requests for
one Veg Burger and some fries. With coming example, we would increase the
customer and mock the actual multi-threading usages.
Here we go:
Let’s create our
service persons first. Assume each job actor as a thread. So we have to create
three threads – shef, packager and counter person. Also, we would need one
thread to act as customer as well.
There are two ways to create a thread, one is to implements
Runnable interface; other is to extend the thread class. The preference criteria between both
approaches can be driven by Inheritance choice. If a class need to extend some other
class, it should go by interface way, otherwise extending
class will do.
In both ways, one abstract method void
run(), need to be override. The processing which we would like to perform by the thread should go in run definition.
Shef, packager and
counterperson can be categorized as service staff and expected to have some
common properties like name, current order and details. Hence I would like to
create an abstract parent class for it.
ServiceStaff.java
public
abstract class
ServiceStaff {
/**
* @param
currentOrderId
* @param
name
*/
public
ServiceStaff(int currentOrderId,
String name,Order order)
{
this.currentOrderId
= currentOrderId;
this.name
= name;
this.order=order;
}
private
Order order;
public
Order getOrder() {
return
order;
}
public
void setOrder(Order order)
{
this.order
= order;
}
private
int currentOrderId;
private
String name;
public
int getCurrentOrderId() {
return
currentOrderId;
}
public
void setCurrentOrderId(int
currentOrderId) {
this.currentOrderId
= currentOrderId;
}
public
String getName() {
return
name;
}
public
void setName(String name)
{
this.name
= name;
}
}
Shef.java
public
class Shef extends
ServiceStaff implements
Runnable {
public
Shef(int currentOrderId,
String name, Order order)
{
super(currentOrderId,
name, order);
}
@Override
public
void run() {
System.out.println(getName()
+ ":Preparing order: "
+
getCurrentOrderId());
try
{
//
Mocking the time consumed by the Shef in preparing the item
Thread.sleep(5000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println(getName()
+ ":Prepared order" +
getCurrentOrderId());
}
}
In above example you must have observed
two different constructs - Thread.sleep(…) and InterruptedException.
Sleep is a static method of class thread, which causes the
current thread to go in idle state for the given time as parameter. Thread is
moved from running to idle till the stated time and restored in runnable state
after it.
InterruptedException is the exception thrown by some methods of thread which drives state of a
thread. When this exception occurs, it meant that some other thread wants to
interrupt the called thread from its current state. More
details will be provided in coming sections of this
article
Packager.java
public
class Packager extends
ServiceStaff implements
Runnable {
public
Packager(int currentOrderId,
String name, Order order)
{
super(currentOrderId,
name, order);
}
@Override
public
void run() {
packageOrder();
}
private
void packageOrder() {
System.out.println(getName()+":Packing
order #" + getCurrentOrderId());
try
{
//
mocking the packaging time
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println(getName()
+ ":Packed order #" +
getCurrentOrderId());
}
}
CounterPerson.java
public
class CounterPerson extends
ServiceStaff implements
Runnable {
public
CounterPerson(int currentOrderId,
String name, Order order)
{
super(currentOrderId,
name, order);
}
/**
* This class demonstrate how to create a thread by implementing
* runnable.
*
* Functionality of this class is mocking the behavior of
CounterPerson * at entry in snacks joint */
@Override
public
void run() {
welcomeCustomer();
processOrder();
calculateBill();
thankCustomer();
}
private
void thankCustomer() {
System.out.println(getName()
+ ":thankCustomer ...");
}
private
void calculateBill() {
System.out.println(getName()
+ ":calculateBill ...");
}
private
void processOrder() {
System.out.println(getName()
+ ":processing Order ...");
System.out.println(getName()
+ ":Processed ...");
}
private
void welcomeCustomer() {
Calendar
cal = Calendar.getInstance();
if
(cal.get(Calendar.AM_PM)
== Calendar.PM)
{
System.out.println(getName()
+ ":Hello ...");
}
else {
System.out.println(getName()
+ ":Good Morning ...");
}
System.out.println(getName()
+ ":What would you like to have");
}
}
Note: These classes are just drafts and
we will keep on modifying them to mock behavior accordingly.
Customer class doesn’t have any hierarchy hence we
can implement it by extending thread class.
Customer.java
public
class Customer extends
Thread {
private
Order order;
private
String customerName;
public
String getCustomerName() {
return
customerName;
}
public
void setCustomerName(String customerName)
{
this.customerName
= customerName;
}
/**
* @param
order
*/
public
Customer(String customerName,
Order order) {
this.customerName
= customerName;
this.order
= order;
}
public
Order getOrder() {
return
order;
}
public
void setOrder(Order order)
{
this.order
= order;
}
/**
* This class demonstrates how to create a
thread by extending thread class.
*
* Functionality of this class is mocking the
behavior of portier at exit in
* snacks Chain joint
*/
@Override
public
void run() {
greetBack();
placeOrder();
payBill();
}
private
void placeOrder() {
System.out.println(customerName
+ ":" + " placing
order ...");
}
}
private
void payBill() {
System.out.println(customerName
+ ":" + "paying
bill ...");
}
}
private
void greetBack() {
Calendar
cal = Calendar.getInstance();
if
(cal.get(Calendar.AM_PM)
== Calendar.PM)
{
System.out.println(customerName
+ ":" + "Hello
...");
}
else {
System.out.println(customerName
+ ":" + "Good
Morning ...");
}
System.out.println(customerName
+ ":" + "I would
like to have");
}
}
We would need some more related entity classes like order,
menu, order item etc.
Item.java
public
class Item {
/**This
class represent single item in the menu or order
* @param
itemName
* @param
cost
*/
public
Item(String itemName, int
cost) {
this.itemName
= itemName;
this.cost
= cost;
}
private
String itemName;
private
int cost;
public
String getItemName() {
return
itemName;
}
public
void setItemName(String itemName)
{
this.itemName
= itemName;
}
public
int getCost() {
return
cost;
}
public
void setCost(int
cost) {
this.cost
= cost;
}
}
Menu.java
public
enum Menu {
VEGBURGER(new
Item("VegBurger", 60)),
PANEERWRAP(new
Item("Paneer Wrap",200)),
FRENCHFRIES(new
Item("French Fries", 80)),
COKE(new
Item("Coke", 30)),
MACPUFF(new
Item("Mac Puff", 20));
final
Item item;
public
Item getItem() {
return
item;
}
Menu(Item
item){
this.item
= item;
}
}
Order.java
public
class Order {
private
int orderId;
private
int totalCost;
private
List<Item> menuItems
= new ArrayList<Item>();
private
String status = "New";
public
String getStatus() {
return
status;
}
public
void setStatus(String status)
{
this.status
= status;
}
public
int getOrderId() {
return
orderId;
}
public
void setOrderId(int
orderId) {
this.orderId
= orderId;
}
public
int getTotalCost() {
return
totalCost;
}
public
void setTotalCost(int
totalCost) {
this.totalCost
= totalCost;
}
public
List<Item> getMenuItems() {
return
menuItems;
}
public
void setMenuItems(List<Item> menuItems)
{
this.menuItems
= menuItems;
}
}
No comments:
Post a Comment