Exiting a Java method completely

764 views Asked by At

My method checkConnection() calls setPort() within a TimeLimiter which exits the call method within 3 seconds if the method isn't finished. This works great and there is an exception of com.google.common.util.concurrent.UncheckedTimeoutException when the time limit is exceeded. However even after this exception is thrown setPort still runs and once completed, code within my try statement opening the port runs however once it gets to Thread.sleep(100) an InterruptedException is thrown then the method exits. However this leaves me with an open port which causes problems. Is there a way once the time limit is exceeded that all code within the call() method will stop?

 public static String checkConnection(final String comPort) {

        final String port = comPort;
        String result = null;

        TimeLimiter limiter = new SimpleTimeLimiter();
        try {

            result = limiter.callWithTimeout(new Callable<String>() {

                public String call() {

                    // Try to set serial port
                    String setPort = setPort(comPort);

                    // Check for any exceptions
                    if(setPort.contains("jssc.SerialPortException")) {

                        if(setPort.contains("Port busy")) {

                            return "Error: The port appears to be busy";

                        } else {

                            return "Error: Can't connect to port";

                        }

                    }

                    try {

                            // Port can't be accessed twice at the same time
                            synchronized(portLock) {

                                // Open port if not already opened
                                if(!serialPort.isOpened())
                                    serialPort.openPort();

                                // Sleep while response is being sent
                                Thread.sleep(300);

                                // Check for response
                                buffer = serialPort.readBytes(6);//Read 6 bytes from serial port

                                serialPort.closePort();

                            }

                        // Parse response as string
                        response = new String(buffer);

                    } catch (SerialPortException | InterruptedException e) {

                        System.out.println("Serial:: ping() :: Exception while pinging Noteu : " + e);

                        return "Error";

                    }

                    return response;

                }
              }, 3, TimeUnit.SECONDS, false);

        } catch (Exception e) {

            System.out.println("Serial:: checkConnection() :: Exception while calling ping : " + e);

        }

    } 



public static String setPort(String port) {

        synchronized(portLock) {

            try {

                System.out.println("Serial:: setPort() :: Opening Port...");

                serialPort = new SerialPort(port);

                if(!serialPort.isOpened())
                    serialPort.openPort();

                System.out.println("Serial:: setPort() :: Setting Params...");

                serialPort.setParams(SerialPort.BAUDRATE_9600, 
                        SerialPort.DATABITS_8,
                        SerialPort.STOPBITS_1,
                        SerialPort.PARITY_NONE);
                System.out.println("Setting Port3");

                serialPort.closePort();

                System.out.println("Serial:: setPort() :: Port Set...");

                return "Success";

            } catch (SerialPortException e) {

                System.out.println("Serial:: setPort() :: Exception at set Port : " + e.toString());

                return e.toString();

            }

        }

    }
2

There are 2 answers

5
Abhijeet Kushe On

Can you try if this works This is the signature of

callWithTimeout(Callable<T> callable,
                long timeoutDuration,
                TimeUnit timeoutUnit,
                boolean amInterruptible)

........
amInterruptible - whether to respond to thread interruption by aborting the operation and throwing InterruptedException; if false, the operation is allowed to complete or time out, and the current thread's interrupt status is re-asserted.

You are passing amInterruptible as false.Can you try passing true and see if it works .Also I have strong feeling setPort has to be interruptible .For that as User Scadge has commented you need to provide its implementations.Anyways just hoping this quick solution might work for you

2
RealSkeptic On

This is the documented behavior of SimpleTimeLimiter:

A TimeLimiter that runs method calls in the background using an ExecutorService. If the time limit expires for a given method call, the thread running the call will be interrupted.

Basically, "interrupting" a thread means that its interrupt flag is set (unless one of the conditions mentioned in the Thread.interrupt() documentation holds). So the flag is just set, without any exceptions thrown within the internal thread (the thread that performs the setPort.

Once that thread gets to the point where it calls sleep(), then the interrupt flag is read and immediately aborts the thread.

What you could do is check the Thread.interrupted() or Thread.isInterrupted() methods, and if there was an interruption, clean up the port (close it, etc.). You could put the whole thing inside the try that catches InterruptedException, and throw InterruptedException if Thread.interrupted() is true after each long operation you perform - setPort, openPort, etc.

In fact, it would be best to do this as early as possible, so maybe inside the implementation of setPort, if it's possible.