• Post Reply Bookmark Topic Watch Topic
  • New Topic

ATM code not working

 
Smriti Awasthi
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello everyone,
If any one has time, can you please look on my code of a Bank ATM. It has a server-client model using sockets. The server has to handle just one client at this time but the requests like deposit , withdraw and check balance should be handled in different "threads" . For now it has to handle just one Account object.
I am stuck with threads, not clear with lock mechanism on this. I get this sort of error on server window :

C:\java cscie160.hw6.Server 7777
Accepting clients now
Client acquired on port #7777, reading from sock
Adding atmRunnableItem to Request Queue
Putting atmRunnableItem on requestQueue
Calling requestQueue.notifyAll()
ERROR: java.lang.IllegalMonitorStateException

and on client window :

C:\>java cscie160.hw6.Client localhost 7777
ATMProxy writing command to server: BALANCE

After this it hangs.....

I am pasting the entire code. If anybody can help me with this, it would be really aprreciated.
 
Henry Wong
author
Sheriff
Posts: 22521
109
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Putting atmRunnableItem on requestQueue
Calling requestQueue.notifyAll()
ERROR: java.lang.IllegalMonitorStateExceptio


In order to call the notifyAll() method on an instance, the thread needs to own the synchronization lock on that instance. If a thread tries to call the method, without the lock, it will get the exception shown.

Henry
 
Smriti Awasthi
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Henry,
As you told, i tried to create locks on it and now i am not getting illegalmonitorexception.
But now what i am getting is weird. My threads are not able to start i think or what is not clear to me.
Can you please take a look on my code :

The output on client side is :

C:\>java cscie160.hw6.Client localhost 7777
ATMProxy writing command to server: BALANCE
Server returned: 0.0
Balance: 0.0
Depositing: 1000
ATMProxy writing command to server: DEPOSIT
ATMProxy writing command to server: BALANCE
Server returned: 0.0 ----------------------------------------------> Server always returns 0 only, even after deposit , after withdraw!!!
Balance: 0.0
Withdrawing: 250
ATMProxy writing command to server: WITHDRAW
ATMProxy writing command to server: BALANCE
Server returned: 0.0 ------------------------------------------------>always 0.
Balance: 0.0
Withdrawing: 750
ATMProxy writing command to server: WITHDRAW
ATMProxy writing command to server: BALANCE
Server returned: 0.0
Balance: 0.0
And on server window i get this :




C:\>java cscie160.hw6.Server 7777
Accepting clients now
Client acquired on port #7777, reading from socket
Thread[Thread-0,5,main]is running
Thread[Thread-3,5,main]is running
ERROR: cscie160.hw6.ATMException: NOT ENOUGH BALANCE
ERROR: cscie160.hw6.ATMException: NOT ENOUGH BALANCE
ERROR: cscie160.hw6.ATMException: NOT ENOUGH BALANCE
Thread[Thread-4,5,main]is running
Thread[Thread-5,5,main]is running
Thread[Thread-6,5,main]is running
Thread[Thread-1,5,main]is running
ERROR: cscie160.hw6.ATMException: NOT ENOUGH BALANCE
ERROR: cscie160.hw6.ATMException: NOT ENOUGH BALANCEjava.net.SocketException: Co
nnection reset
at java.net.SocketInputStream.read(Unknown Source)
at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)

Thread[Thread-2,5,main]is running
at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
at sun.nio.cs.StreamDecoder.read(Unknown Source)
ERROR: cscie160.hw6.ATMException: NOT ENOUGH BALANCE
ERROR: cscie160.hw6.ATMException: NOT ENOUGH BALANCE
ERROR: cscie160.hw6.ATMException: NOT ENOUGH BALANCE
ERROR: cscie160.hw6.ATMException: NOT ENOUGH BALANCE
ERROR: cscie160.hw6.ATMException: NOT ENOUGH BALANCE
ERROR: cscie160.hw6.ATMException: NOT ENOUGH BALANCE
ERROR: cscie160.hw6.ATMException: NOT ENOUGH BALANCE
ERROR: cscie160.hw6.ATMException: NOT ENOUGH BALANCE at java.io.InputStreamRe
ader.read(Unknown Source)
at java.io.BufferedReader.fill(Unknown Source)
ERROR: cscie160.hw6.ATMException: NOT ENOUGH BALANCE

at java.io.BufferedReader.readLine(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at cscie160.hw6.Server.serviceClient(Server.java:42)
at cscie160.hw6.Server.main(Server.java:69)
 
Henry Wong
author
Sheriff
Posts: 22521
109
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Smriti Awasthi wrote:
As you told, i tried to create locks on it and now i am not getting illegalmonitorexception.
But now what i am getting is weird. My threads are not able to start i think or what is not clear to me.
Can you please take a look on my code :


There is a very important reason why holding the lock is mandatory. It is needed because there is a race condition that can't be solved unless the wait() method does the releasing and reacquiring of the lock. The race condition is actually very complex.

Regardless, if you just wrapped it in a lock, in order to bypass the exception -- you stand a good chance of running right into the race condition. Or even others, if you don't take care to avoid them.


If you can post a small reproduceable snippet of the code, we should be able to take a look at it here.

Henry

 
Smriti Awasthi
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Preview
ATM code not working
// This is the server code.

import java.net.*;
import java.io.*;
import java.util.StringTokenizer;
import java.util.*;

public class Server {

private ServerSocket serverSocket;
public static ATMImplementation atmImplementation;
private BufferedReader bufferedReader;
List<ATMRunnable> requestQueue; //= new ArrayList<ATMRunnable>();
ATMThread[] atmthread = new ATMThread[5];
private Object lock1 = new Object();
public Server(int port) throws java.io.IOException,InterruptedException
{
serverSocket = new ServerSocket(port);
atmImplementation = new ATMImplementation();
requestQueue = Collections.synchronizedList(new ArrayList<ATMRunnable>()); }

/** serviceClient accepts a client connection and reads lines from the socket.
* Each line is handed to executeCommand for parsing and execution.
*/
public void serviceClient (ATMImplementation atmImplementation) throws java.io.IOException,InterruptedException
{
System.out.println("Accepting clients now");
Socket clientConnection = serverSocket.accept();

// Arrange to read input from the Socket
InputStream inputStream = clientConnection.getInputStream();
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
// Arrange to write result across Socket back to client
OutputStream outputStream = clientConnection.getOutputStream();
// PrintStream printStream = new PrintStream(outputStream);

System.out.println("Client acquired on port #" + serverSocket.getLocalPort() + ", reading from socket");

String commandLine;
for(int i=0;i<5;i++)
{ while((commandLine = bufferedReader.readLine()) != null)
{try { ATMRunnable atmrunnable = new ATMRunnable(commandLine,outputStream,atmImplementation);
synchronized(lock1)
{requestQueue.add(atmrunnable);}
}catch (Exception atmex) {
System.out.println("ERROR: " + atmex);
}
atmthread[i]=new ATMThread(requestQueue); // here i create ATMThread objects which in turn start threads.
}
lock1.notifyAll(); }
}

public static void main(String argv[])
{
int port = 1099;
if(argv.length > 0) {
try {
port = Integer.parseInt(argv[0]);
} catch (Exception e) { }
}
try {
Server server = new Server(port);
server.serviceClient(atmImplementation);
System.out.println("Client serviced");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

// ATMThread code :

import java.util.StringTokenizer;
import java.io.*;
import java.net.*;
import java.util.*;
class ATMThread
{ Thread t;

private Object lock1 = new Object();
public ATMThread(List<ATMRunnable> requestQueue) throws InterruptedException
{ t = new Thread(processrequestQueue(requestQueue));
t.start();
}


public ATMRunnable processrequestQueue(List<ATMRunnable> requestQueue) throws InterruptedException
{ ATMRunnable atmRunnableItem=null;
synchronized(lock1)
{ while(requestQueue.isEmpty())
{ try{ requestQueue.wait();
} catch (InterruptedException e)
{e.printStackTrace(); }
}
Iterator<ATMRunnable> iterator = requestQueue.iterator();
if(iterator.hasNext())
{ atmRunnableItem = iterator.next();
iterator.remove();
}
lock1.notifyAll();
return atmRunnableItem;
}
}
}

// ATMRunnable has run() method.

// Here is the code for ATMRunable :


import java.util.StringTokenizer;
import java.io.*;
import java.net.*;
import java.util.*;

class ATMRunnable implements Runnable{
Socket clientConnection;
//PrintStream printStream;
ATMImplementation atmImplementation;

private Object lock1 = new Object();
private String commandLine;
OutputStream outputStream;
PrintStream printStream;

public ATMRunnable(String commandLine,OutputStream outputStream,ATMImplementation atmImplementation)
{ this.commandLine = commandLine;
this.atmImplementation=atmImplementation;
this.outputStream=outputStream;


}

public String getCommandLine()
{ return commandLine;
}

public void run()
{
synchronized(lock1)
{System.out.println(Thread.currentThread() + "is running");
printStream = new PrintStream(outputStream);
while(this.commandLine!=null)
{
try{

Float result = executeCommand(this.commandLine);

if(result != null) { // Only BALANCE command returns non-null
printStream.println(result); // Write it back to the client
}
}
catch (ATMException atmex) {
System.out.println("ERROR: " + atmex);
}

}
}
lock1.notifyAll();
}

private Float executeCommand(String commandLine) throws ATMException {
// Break out the command line into String[]

StringTokenizer tokenizer = new StringTokenizer(commandLine);
String commandAndParam[] = new String[tokenizer.countTokens()];
int index = 0;
while(tokenizer.hasMoreTokens()) {
commandAndParam[index++] = tokenizer.nextToken();
}
String command = commandAndParam[0];
// Dispatch BALANCE request without further ado.
if(command.equalsIgnoreCase(Commands.BALANCE.toString())) {
return this.atmImplementation.getBalance();

}

// Must have 2nd arg for amount when processing DEPOSIT/WITHDRAW commands
if(commandAndParam.length < 2) {
throw new ATMException("Missing amount for command \"" + command + "\"");
}
try {
float amount = Float.parseFloat(commandAndParam[1]);
if(command.equalsIgnoreCase(Commands.DEPOSIT.toString())) {
this.atmImplementation.deposit(amount);


}
else if(command.equalsIgnoreCase(Commands.WITHDRAW.toString())) {
this.atmImplementation.withdraw(amount);

} else {
throw new ATMException("Unrecognized command: " + command);
}
} catch (NumberFormatException nfe) {
throw new ATMException("Unable to make float from input: " + commandAndParam[1]);
}

// BALANCE command returned result above. Other commands return null;

return null;


}
}

This is the code to be checked. rest all seems fine.
 
Ireneusz Kordal
Ranch Hand
Posts: 423
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You have three 'lock1' objects:
- one defined in the Server class
- second defined in the ATMThread class
- third defined in the ATMRunnable class

In the Server class you add items to the queue and call notifyAll on the lock1 from the Server class



In the ATMThread class your threads check queue and if the queue is empty call wait()
... but on requestQueue object while you synchronize on the lock1 object from the ATMThread class:

This cause exception IllegalMonitorState, because wait() could be called only on object on which you have obtained the monitor (with synchronize keyword)

Here in the ATMRunnable code you have this:

This notifies on the third lock1 object ;)


You must synchronize and call wait and notify on the same object in all code fragments.
I think the best to wait and notify on would be requestQueue object.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!