I am executing a simple command where user gives the options(args) and I made a logic to get the args in Java program in which I am using wait() for particular time so that command will take that much minimum time to execute.I am saving some data in a file after that.
Within this time if the user wants to end the process ,should be able to stop the process smoothly by giving input like "exit" in the command prompt.
Please help.
The standard way of interrupting a command line program is by adding a Ctrl-C handler to your app:
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
// cleanup logic here
}
});
See this question for more details.
Since you insist. Here is an implementation when commands are executed in background threads. I hope the complexity of this example will deter you from implementing it:
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Shell {
private static final int NUM_PARALLEL_COMMANDS = 5;
private static final int SLEEP_DURATION = 1000;
public static void main(String[] args) throws InterruptedException {
ExecutorService executor =
Executors.newFixedThreadPool(NUM_PARALLEL_COMMANDS);
try (Scanner scanner = new Scanner(System.in)) {
String command = null;
int counter = 0;
do {
command = scanner.nextLine();
switch (command) {
case "DoStuff":
executor.submit(NewDoStuffCommand(++counter));
break;
}
} while (!command.equals("exit"));
}
executor.shutdownNow();
executor.awaitTermination(1, TimeUnit.SECONDS);
}
private static Runnable NewDoStuffCommand(final int counter) {
return new Runnable() {
#Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
System.out.println(counter + ": Doing time consuming things...");
Thread.sleep(SLEEP_DURATION);
}
System.out.println(counter + ": Finished.");
} catch (InterruptedException e) {
System.out.println(counter + ": Command interrupted :(");
// do cleanup
Thread.currentThread().interrupt();
}
}
};
}
}
Related
I'm having some trouble with Jline and not quite understanding how to work it properly, everything seems to work from the examples but when i attempt to move it into my console application things go weird.
I've come across two issues:
When you write input into the console while something else is logging a message via System out, the written input gets broken. (View: https://i.imgur.com/ZAJDjTI.png)
I attempted to sync the commands to the main thread since the reader thread will be blocking, but this time you'll find that this causes the output text to take over the commands input space.
((Green text is the input, white is output)View: https://i.imgur.com/CdKiIYy.png)
The output i expected was for input coming from the bottom of the console to be unaffected by the output of the console, leaving a smooth input text layer at the bottom. (View: https://i.imgur.com/HfH5l8U.png?1)
Here's an example class i wrote to demonstrate the two problems I'm having:
import jline.console.ConsoleReader;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.locks.ReentrantLock;
public class Example {
private ConsoleReader consoleReader;
private LinkedList<Runnable> syncQueue = new LinkedList<>();
private ReentrantLock lock = new ReentrantLock();
public Example() {
try {
this.consoleReader = new ConsoleReader();
this.consoleReader.setExpandEvents(false);
} catch (IOException e) {
e.printStackTrace();
}
//If you enable this, Jline seems to be disrupted by the System out.
// startStopwatch();
setupJline();
//Ticker, its ugly i know
while (true) {
lock.lock();
try {
while (syncQueue.size() > 0) {
Runnable runnable = syncQueue.poll();
try {
runnable.run();
} catch (Exception e) {
e.printStackTrace();
}
}
} finally {
lock.unlock();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private void setupJline() {
new Thread("Console Thread") {
#Override
public void run() {
while (true) {
try {
String line = consoleReader.readLine(">");
if (line != null && line.trim().length() > 0) {
//Lets pass this on as an instruction to our program
//Sync seems okay, output wise
handleInstructionSynced(line);
//async seems to mess things up though, comment the handleInstructionSynced method and
//uncomment the Async one to see what i mean.
//handleInstructionAsync(line);
}
consoleReader.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
}
//Just a dummy example instruction handler
private void handleInstructionAsync(String input) {
System.out.println("You've input \"" + input + "\" as your instruction.");
}
private void handleInstructionSynced(String input) {
runSync(() -> System.out.println("You've input \"" + input + "\" as your instruction."));
}
private void runSync(Runnable runnable) {
lock.lock();
try {
syncQueue.add(runnable);
} finally {
lock.unlock();
}
}
private void startStopwatch() {
Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
int time = 0;
#Override
public void run() {
System.out.println(time + " seconds counted");
time++;
}
};
timer.scheduleAtFixedRate(timerTask, 0, 1000);
}
public static void main(String[] args) {
new Example();
}
}
Any solutions?
I have an Java console application, where I constantly read user input for commands. Some of the commands have to run in a different thread and just print to the output results of their run periodically, once in 10 seconds. How do I do that without affecting a user.
Example:
ruHello!n
Which means while user was typing the 'run' command, a thread made an output to console.
Is there a standard way to omit this?
You could use a Semaphore to deal with this shared resource among many threads.
I wrote a simple example based on this link. Below is the main class that gets input from the console.
package multithread;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class MainThread {
public static void main(String[] args) throws IOException, InterruptedException {
System.out.println("Starting...");
Semaphore semaphore = new Semaphore(1);
ExecutorService execService = Executors.newFixedThreadPool(8);
for (int i = 0; i < 100; i++) {
execService.submit(new BackgroundTask(semaphore, i));
}
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String line;
for (int i = 0; i < 10; i++) {
semaphore.acquire();
System.out.print("$ ");
line = reader.readLine();
System.out.println(line);
semaphore.release();
Thread.sleep(1000);
}
reader.close();
execService.awaitTermination(10, TimeUnit.MINUTES);
}
}
And here is the background task class that prints to the console.
package multithread;
import java.util.concurrent.Semaphore;
public class BackgroundTask implements Runnable {
private Semaphore semaphore;
private int id;
public BackgroundTask(Semaphore semaphore, int id) {
this.semaphore = semaphore;
this.id = id;
}
#Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
semaphore.acquire();
System.out.println("Hello from " + id);
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
So I'm trying to read user input using the Scanner class. Is there a simple way to make it so that after 10 seconds it moves onto the next block of code? Thanks
You can use Timer and TimerTask. TimerTask will allow you to run a task after a certain amount of time, in this case you can use this task to stop waiting for the user.
import java.util.Timer;
import java.util.TimerTask;
...
TimerTask task = new TimerTask()
{
public void run()
{
if( str.equals("") )
{
System.out.println( "you input nothing. exit..." );
System.exit( 0 );
}
}
};
...
Timer timer = new Timer();
timer.schedule( task, 10*1000 );
Scanner sc = new Scanner(System.in);
String in = sc.readLine();
timer.cancel();
So if the user doesn't respond within 10 seconds here, the timer will quit reading input. I stole/adapted this response from this initial post:
Time limit for an input
I found another approach where we can continue our flow after the timeout instead of terminating the program.
That can be done via ScheduledExecutorService class.
The logic implemented is
Initialize a variable for managing the input state and another one for storing the result. (The input I wanted was boolean)
Schedule the input task at a 0s delay (i.e ask for input immediately)
Schedule another task to check for the input status as per the specified delay
Wait for both the tasks to be completed
Return the result
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
...
//member variables of class
private static AtomicBoolean inputValue = new AtomicBoolean(true);
private static AtomicBoolean inputEntered = new AtomicBoolean(false);
private static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
...
public static void main(String[] args) {
try {
boolean yes = getTimedInput("Enter yes or no", 5);
} catch (Exception e) {
e.printStackTrace();
}
}
...
public static boolean getTimedInput(String inputString, long timeoutInSeconds) throws Exception {
System.out.printf("%s [Y/n] [timeout=%ds] >> ", inputString.trim(), timeoutInSeconds);
scheduler.schedule(() -> {
try {
String s = br.readLine();
if (s != null) {
inputValue.set(s.trim().equalsIgnoreCase("y"));
}
inputEntered.set(true);
} catch (IOException e) {
}
}, 0, TimeUnit.SECONDS);
scheduler.schedule(() -> {
if (inputEntered.get()) {
inputEntered.set(false);
} else {
System.out.println("\nInput timed out. Considering it as Y");
inputValue.set(true);
}
}, 0, TimeUnit.SECONDS);
scheduler.awaitTermination(timeoutInSeconds + 1, TimeUnit.SECONDS);
System.out.println();
return inputValue.get();
}
I'm creating a program that prints the sound of three bells.
I need to stop the process when the user types a key on the keyboard, how can I do?
Also, I would make sure that every bell show your sound in a random time, making use of the property Math.random(). You can associate a random time to a thread?
package campane;
import java.io.*;
import java.util.*;
public class GestioneCampane extends Thread {
public static void main(String [] args) {
BufferedReader tast = new BufferedReader(new InputStreamReader(System.in));
char pressione;
Campane campana = new Campane("DIN", 300);
Campane campana2 = new Campane("DON", 1000);
Campane campana3 = new Campane("DAN", 2000);
campana.start();
campana2.start();
campana3.start();
}
}
this is the second class
package campane;
public class Campane extends Thread {
private String campane; // word to print
private int delay;
public Campane(String whatToSay, int delayTime) {
campane = whatToSay;
delay = delayTime;
}
public void run() {
try {
while(true) {
System.out.print(campane + " ");
Thread.sleep(delay);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
You can stop a thread by interrupting it:
Thread.interrupt()
You can stop a thread for a given time, and continue with it after the time is consumed:
Long time = 15000L; // in milliseconds
Thread.sleep(time);
Use KeyBindings to intercept keys pressed and randomize your sound relevence, this example can save time
How do I break an infinity loop, like this one:
while(true){
if(???){
break;
}
}
Whitout interrupting it every time it loops and ask for input? The loop has to loop continuous until the user breaks it.
EDIT
I want to break it with a key input.
You could put the cycle in a separate thread.
import java.*;
import java.io.*;
class Main {
public static void main(String[] args) throws IOException {
Thread t = new Thread(new Runnable() {
public void run() {
int cnt = 0;
while (true) {
System.out.println(cnt);
++cnt;
}
}
});
t.start();
System.in.read();
t.stop();
}
}
Let's analyze it line by line; first the imports:
import java.*;
import java.io.*;
class Main {
Then we need to declare that main throws IOException, because we'll be dealing with IO calls; a better option is obviously to correctly handle exceptions, but this is just a simple test.
public static void main(String[] args) throws IOException {
Then we create a thread which executes an infinite cycle; we will not be doing IO calls from this thread. The thread is not started until we call Thread.start(), and will run until we call Thread.stop().
Thread t = new Thread(new Runnable() {
public void run() {
int cnt = 0;
while (true) {
System.out.println(cnt);
++cnt;
}
}
});
Now we start the thread; the lines after this call will keep executing concurrently with the thread, so we will be able to wait for user input and stop the thread.
t.start();
System.in.read();
t.stop();
}
}
I think your best option is to use a flag controlled by another thread. You could do something like this:
private volatile boolean keepRunning = true;
public synchronized void stopRunning() {
keepRunning = false;
}
public void someProcess() {
new Thread() {
public void run() {
try (Scanner scanner = new Scanner(System.in)) {
keepWaiting = true;
while(keepWaiting) {
String userInput = scanner.next();
if("s".equals(userInput)) {
stopRunning();
keepWaiting = false;
}
}
}
}
}.start();
while(keepRunning){
doWork();
}
}
The loop should keep running until the user enters "s". Of course it's a very basic implementation but you get the idea.
Also, you don't really need the "stopRunning()" method, the thread could access the flag directly, but you would need it if you wanted to run the thread from somewhere else.
It is better to use this.
boolean doLoop = true;
while(doLoop){
if(userTerminates()){ //user terminates it?
doLoop = false;
}
}
private boolean userTerminates(){
Scanner scanner = new Scanner(System.in);
//If you want that user terminates it with 'c' char
return scanner.nextLine().equals("c");
}