I have been working on a long project trying to understand the basics of multi-threading. The application is supposed to simulate a Shop and a Customer which share a Box and a PayPal account.
Main.Java
package exe5;
public class Main {
static Thread mainThread = Thread.currentThread();
public static void main(String[] args) throws InterruptedException{
Box box = new Box();
PayPalAcc pp1 = new PayPalAcc();
mainThread.setName("mainThread");
Thread DaniCustomerThread = new Thread(new Customer(box, pp1, "Daniel Netzer"), Customer.getName());
Thread POShopThread = new Thread (new Shop(box, pp1, "Post Office"), Shop.getName());
DaniCustomerThread.start();
POShopThread.start();
Thread.sleep(5);
// Closing all loops and adding signature to log of safe closure.
DaniCustomerThread.interrupt();
POShopThread.interrupt();
Thread.sleep(100); // Allowing main thread a bit more to actually get the signature for safe closure for both threads.
}
}
Customer.java
package exe5;
public class Customer implements Runnable{
private static Box box;
private static PayPalAcc paypal;
private static String name;
private static Object customerLock = new Object();
public Customer(Box box,PayPalAcc paypal, String name){
Customer.box = box;
Customer.name = name;
Customer.setPaypal(paypal);
}
public static Object getCustomerLockMonitor(){
return Customer.customerLock;
}
public static String getName() {
return name;
}
// Unused Getters/Setters
/*private synchronized void setName(String name) {
Customer.name = name;
}
private static Box getBox() {
return box;
}
private synchronized void setBox(Box box) {
Customer.box = box;
}*/
private static PayPalAcc getPaypal() {
return paypal;
}
private static synchronized void setPaypal(PayPalAcc paypal) {
Customer.paypal = paypal;
}
private synchronized void printsCustomer(int caseNum){
switch(caseNum){
case 1: System.out.println(Customer.getName() +" package have been withdrawed from his box at " +Shop.getName());
break;
case 2: System.out.println(Customer.getName() +" deposited money into shared PayPal account.");
break;
case 3: System.out.println(Customer.getName() +" box is empty, waiting for a new package to arrive.");
break;
case 4: System.out.println("closing safely " +Thread.currentThread().getName() +" thread.");
break;
}
}
private synchronized void withdrawBox(){
Customer.box.setBoxStatus(false);
printsCustomer(1);
synchronized(Shop.getShopBoxMonitor()){
Shop.getShopBoxMonitor().notify();}
}
private synchronized void depositInPayPal(int amountToDeposit){
Customer.getPaypal().setPayPalAccStatus(Customer.getPaypal().getPayPalAccStatus() + amountToDeposit);
printsCustomer(2);
synchronized (Shop.getShopPPMonitor()){
Shop.getShopPPMonitor().notify();}
}
@Override
public void run() {
while(Main.mainThread.isAlive()){
while(!box.isBoxStatus()){
synchronized(Customer.getCustomerLockMonitor()){
try {
printsCustomer(3);
depositInPayPal(100);
Customer.getCustomerLockMonitor().wait();
} catch (InterruptedException e) {
printsCustomer(4);
Thread.currentThread().interrupt();
break;
}
}
}
if (Thread.currentThread().isInterrupted()) { break; }
withdrawBox();
}
}
}
Shop.java
package exe5;
public class Shop implements Runnable{
private static Box box;
private static PayPalAcc paypal;
private static String name;
private static Object shopBox = new Object();
private static Object shopPP = new Object();
public Shop(Box box,PayPalAcc paypal, String name){
Shop.box = box;
Shop.name = name;
Shop.setPaypal(paypal);
}
public static Object getShopBoxMonitor(){
return Shop.shopBox;
}
public static Object getShopPPMonitor() {
return Shop.shopPP;
}
public static void setShopPP(Object shopPP) {
Shop.shopPP = shopPP;
}
public static String getName() {
return name;
}
// Unused Getters/Setters
/*private synchronized void setName(String name) {
Shop.name = name;
}
private static Box getBox() {
return box;
}
private synchronized void setBox(Box box) {
Shop.box = box;
}*/
private static PayPalAcc getPaypal() {
return paypal;
}
private static synchronized void setPaypal(PayPalAcc paypal) {
Shop.paypal = paypal;
}
private synchronized void depositBox(){
Shop.box.setBoxStatus(true);
printsShop(1);
synchronized(Customer.getCustomerLockMonitor()){
Customer.getCustomerLockMonitor().notify();}
}
private synchronized void withdrawFromPayPal(int amountToWithdraw){
Shop.getPaypal().setPayPalAccStatus(Shop.getPaypal().getPayPalAccStatus() - amountToWithdraw);
printsShop(2);
}
private synchronized void printsShop(int caseNum){
switch(caseNum){
case 1: System.out.println(Shop.getName() +" deposited new package in " +Customer.getName() +" box.");
break;
case 2: System.out.println(Shop.getName() +" withdrawed money from shared PayPal account.");
break;
case 3: System.out.println(Shop.getName() +" box is full, waiting for customer withdrawal.");
break;
case 4: System.out.println(Customer.getName() +" did not deposited money into PayPal account yet.");
break;
case 5: System.out.println("closing safely " +Thread.currentThread().getName() +" thread.");
break;
}
}
@Override
public void run() {
while(Main.mainThread.isAlive()){
while(Shop.getPaypal().getPayPalAccStatus() < 100){
synchronized(Shop.getShopPPMonitor()){
try {
printsShop(4);
Shop.getShopPPMonitor().wait();
} catch (InterruptedException e) {
printsShop(5);
Thread.currentThread().interrupt();
break;
}
}
withdrawFromPayPal(100);
while(box.isBoxStatus()){
synchronized(Shop.getShopBoxMonitor()){
try {
printsShop(3);
Shop.getShopBoxMonitor().wait();
} catch (InterruptedException e) {
printsShop(5);
Thread.currentThread().interrupt();
break;
}
}
}
depositBox();
}
if (Thread.currentThread().isInterrupted()) { break; }
}
}
}
Box.java
package exe5;
public class Box {
private static boolean boxStatus;
public Box(){
Box.boxStatus = false;
}
public boolean isBoxStatus() {
return boxStatus;
}
public void setBoxStatus(boolean boxStatus) {
Box.boxStatus = boxStatus;
}
}
PayPalAcc.java
package exe5;
public class PayPalAcc {
private static int payPalAccStatus;
public PayPalAcc(){
this.setPayPalAccStatus(0);
}
public int getPayPalAccStatus() {
return payPalAccStatus;
}
public void setPayPalAccStatus(int payPalAccStatus) {
PayPalAcc.payPalAccStatus = payPalAccStatus;
}
}