I'm trying to write a loop which runs until I type a specific text in console where the application is running. Something like:
while (true) {
try {
System.out.println("Waiting for input...");
Thread.currentThread();
Thread.sleep(2000);
if (input_is_equal_to_STOP){ // if user type STOP in terminal
break;
}
} catch (InterruptedException ie) {
// If this thread was intrrupted by nother thread
}}
And I want it to write a line each time it pass through so I do not want it to stop within the while and wait for next input. Do I need to use multiple threads for this?
Do I need to use multiple threads for this?
Yes.
Since using a Scanner on System.in implies that you're doing blocking IO, one thread will need to be dedicated for the task of reading user input.
Here's a basic example to get you started (I encourage you to look into the java.util.concurrent package for doing these type of things though.):
import java.util.Scanner;
class Test implements Runnable {
volatile boolean keepRunning = true;
public void run() {
System.out.println("Starting to loop.");
while (keepRunning) {
System.out.println("Running loop...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
System.out.println("Done looping.");
}
public static void main(String[] args) {
Test test = new Test();
Thread t = new Thread(test);
t.start();
Scanner s = new Scanner(System.in);
while (!s.next().equals("stop"));
test.keepRunning = false;
t.interrupt(); // cancel current sleep.
}
}
Yes, you would need two threads for this. The first could do something like this:
//accessible from both threads
CountDownLatch latch = new CountDownLatch(1);
//...
while ( true ) {
System.out.println("Waiting for input...");
if ( latch.await(2, TimeUnit.SECONDS) ) {
break;
}
}
And the other:
Scanner scanner = new Scanner(System.in);
while ( !"STOP".equalsIgnoreCase(scanner.nextLine()) ) {
}
scanner.close();
latch.countDown();
Related
I'm writing a Java program in which I read a line from Console, and do some processing around it. The processing might take 1-2 seconds (i.e. takes longer than the input rate), while I might keep receiving 50 lines per second.
Although there were some similar questions, they were addressing C/C++ and not Java. So my fundamental question is below:
While still processing an input/line, am I blocked from receiving new inputs? Or somehow they are queued in the system/JVM? Or better ask this way: Do I miss any lines while processing takes time? I don't want to miss any lines by any means.
Here is my code snippet:
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
//process line. Can take 1-2 seconds.
processInput(sc.nextLine());
}
sc.close();
UPDATE:
As suggested, I came up with making my code more thread-friendly, using Executors:
ExecutorService executorService = Executors.newFixedThreadPool(10);
while (sc.hasNext()) {
executorService.submit(new Runnable() {
public void run() {
processInput(sc.nextLine());
}
});
}
Just compare these two samples:
Frist, linear without multiple threads:
public class SampleClass {
public static void main(String[] args) {
SampleClass instance = new SampleClass();
instance.start();
}
private void start() {
Scanner sc = new Scanner(System.in);
String input;
while (!(input = sc.nextLine()).equals("exit")) {
processInput(input);
}
sc.close();
}
private void processInput(String input) {
try {
Thread.sleep(2000);
System.out.println("input: " + input);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Then, using a new thread for every input processing:
public class SampleClass {
public static void main(String[] args) {
SampleClass instance = new SampleClass();
instance.start();
}
private void start() {
Scanner sc = new Scanner(System.in);
String input;
while (!(input = sc.nextLine()).equals("exit")) {
processInput(input);
}
sc.close();
}
private void processInput(String input) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(2000);
System.out.println("input: " + input);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
}
}
Just try it. In both cases you don't miss input, but the difference is that without new threads the processing time adds up (of course) - it doesn't run parallel.
It is blocking, although the documentation could have been clearer: It keeps saying "A scanning operation may block waiting for input." While it could theoretically throw a NoSuchElementException instead of blocking, it seems to me that this is up to the implementation.
Suppose I have two files name A and B. If,
File A contains:
Hi.
How are you?
File B contains:
My name is Ayush.
I'm doing Great.
Output:
HI.
My name is Ayush.
How are you?
I'm doing Great.
As I know we can only request the JVM and if the other thread in the queue is not ready the next thread is executed again. I have tried using flags and set Priority, but I always get the random output. Sometimes the line from second file B is read first and sometimes from the file A. It disturbs the order in which I want an answer.
import java.io.*;
import java.util.*;
class Synchronization{
public void readFromFile(Scanner sc) throws Exception{
while(sc.hasNext()){
System.out.println(sc.nextLine());
Thread.sleep(500);
}
}
}
class SynchronizedThreads extends Thread{
#Override
public void run(){
Scanner sc;
if(Thread.currentThread().getName().equals("A")){
try{
sc = new Scanner(new File("FirstFile.txt"));
object.readFromFile(sc);
}catch(Exception ex){
System.out.println(ex);
}
}else if(Thread.currentThread().getName().equals("B")){
try{
sc = new Scanner(new File("SecondFile.txt"));
object.readFromFile(sc);
}catch(Exception ex){
System.out.println(ex);
}
}
}
public static void main(String[] args) {
Synchronization object = new Synchronization();
SynchronizedThreads t1 = new SynchronizedThreads(object);
SynchronizedThreads t2 = new SynchronizedThreads(object);
//SynchronizedThreads t = new SynchronizedThreads(object);
t1.setName("A");
t2.setName("B");
//t.setName("Temp");
//t.start();
//t1.setPriority(10);
//t2.setPriority(5);
t1.start();
t2.start();
}
}
Second Code
import java.util.*;
import java.io.*;
class ConcurrencyControl extends Thread{
volatile static boolean sema = true;
private String pathForFirstFile = "FirstFile.txt";
private String pathForSecondFile = "SecondFile.txt";
#Override//run() Method
public void run(){
String threadName = Thread.currentThread().getName();
if(threadName.equals("FirstFile")){
try{
Scanner sc = new Scanner(new File(pathForFirstFile));
if(sema == true){
while(sc.hasNextLine() /*&& sema == true*/){
System.out.println(sc.nextLine());
sema = false;
sleep(500);
}
}else{
sleep(500);
}
}catch(Exception ex){
System.out.println(ex);
}
}
else if(threadName.equals("SecondFile")){
try{
Scanner sc1 = new Scanner(new File(pathForSecondFile));
if(sema == false){
while(sc1.hasNextLine() /*&& sema == false*/){
System.out.println(sc1.nextLine());
sema = true;
sleep(500);
}
}else{
sleep(500);
}
}catch(Exception ex){
System.out.println(ex);
}
}
}
public static void main(String[] args){
ConcurrencyControl threadOne = new ConcurrencyControl();
threadOne.setName("FirstFile");
ConcurrencyControl threadSecond = new ConcurrencyControl();
threadSecond.setName("SecondFile");
threadOne.start();
threadSecond.start();
}
}
Have a flag say isATurn. Initially set isATurn to true. Create two threads call in the order. Put your conditional statements inside a synchronized block to check for the turns and process it accordingly. You have to invert the flag everytime you process the file.
public void processA() {
while (!isATurn); //wait till processB method to invert the flag
synchronized(this) {
processNow();
isATurn = !isATurn;
}
}
Implement processB method in the same manner.
Edit: Thread.sleep() is slightly low level and achieving thread safety using that is more difficult. Java provides us with synchronized keyword to deal with these problems in a more elegant way.
Edit: Moved busy waiting outside the synchronized block to avoid poor CPU utilization.
I´ve got a problem exiting a thread in the right way. I adapted some code that helps me running a executable in a Commandline window from my code. Until this the code works fine. The problem is that after the program that I´m calling is finished and returns to command line, one thread keeps running, How do I get the information which one is finished and how do I kill it afterwards properly? I already tried several options with wait and notify but I couldn´t get them to work. Thanks for the help, that´s my code:
public class InnExec {
String wkdir;
static String ActCommand;
static String InFile;
InnExec(String wkdir, String ActCommand, String InFile) {
InnExec.ActCommand=ActCommand;
this.wkdir=wkdir;
InnExec.InFile=InFile;
}
public Process Run() throws IOException, InterruptedException {
File wkdir=new File(this.wkdir);
ProcessBuilder processBuilder= new ProcessBuilder();
Boolean Windows=true;
if (!System.getProperty("os.name").contains("Windows")){
Windows=false;
}
if(Windows){
processBuilder.command("cmd.exe").redirectErrorStream(true);
}
else{
processBuilder.command("/bin/bash").redirectErrorStream(true);
}
processBuilder.directory(wkdir);
Process process = processBuilder.start();
Thread processOutputHandlerThread=createAndStartProcessOutputHandlerThread(process);
Thread processInputHandlerThread =createAndStartProcessInputHandlerThread(process);
return process;
}
private static Thread createAndStartProcessInputHandlerThread(final Process process) {
Thread thread = new Thread(new Runnable() {
public void run() {
PrintWriter printWriter = new PrintWriter(process.getOutputStream());
//Scanner scanner = new Scanner(System.in);
try {
printWriter.println(ActCommand+"<"+InFile);
printWriter.flush();
Thread.sleep(50);
}
catch (InterruptedException interruptedException) {
//
}
}
});
thread.start();
return thread;
}
private static Thread createAndStartProcessOutputHandlerThread(final Process process) {
Thread thread = new Thread(new Runnable() {
public void run() {
try {
char c = Character.MAX_VALUE;
while ((c = (char) process.getInputStream().read()) != Character.MAX_VALUE) {
System.out.print(c);
// Ausgabe auf Java Console
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
thread.start();
return thread;
}
}
You could use CountDownLatch
In your main method, you could define how many threads you would have, inject it within each of your threads and wait for their completion. Once a thread completes, its would call countdown api and once all your thread completes, your main method can continue further.
I am getting unexpected behavior when using console.writer() in multiple threads. In the below example, when program starts, I spawn a second thread, which is supposed to print to the console "Simulating Error." every second. Then the main thread is supposed to print to the console when you type something like "get status 9999":
public class NewConsoleExample {
private volatile boolean running=true;
private Lock lock = new ReentrantLock();
public void startService(){
Console cnsl = null;
try{
cnsl = System.console();
if (cnsl != null) {
while(running){
String input = cnsl.readLine("<console>: ");
String[] msg = input.split(" ");
if(msg.length == 3){
if(msg[0].equals("get")){
lock.lock();
cnsl.writer().println(input);
lock.unlock();
}
}
}
}
}catch(Exception ex){
ex.printStackTrace();
}
}
public void startThreadInterrupt(){
Thread consoleInterrupt = new Thread(new Runnable(){
public void run() {
Console cnsl = null;
try {
cnsl = System.console();
if (cnsl != null) {
while(running){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.lock();
cnsl.writer().println("Simulating Error.");
lock.unlock();
}
}
} catch(Exception ex){
ex.printStackTrace();
}
}
});
consoleInterrupt.start();
}
public static void main(String[] args) {
NewConsoleExample console = new NewConsoleExample();
console.startThreadInterrupt();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
console.startService();
}
}
Instead what happens is after "Simulating Error" is printed the first time, it is only ever printed again when you enter a pattern like "get status 9999". These are two entirely different threads with different behavior. Why is the other thread printing "Simulating Error" only when the main thread gets input like "get status 9999". The other thread should be printing "Simulating Error" every second regardless of what's going on in main thread.
Its cause the readLine() locks the Console object, so any other thread that tries to write on it waits for the lock to be free.
Check the docs for Console
Quote from docs:
Read and write operations are synchronized to guarantee the atomic
completion of critical operations; therefore invoking methods
readLine(), readPassword(), format(), printf() as well as the read,
format and write operations on the objects returned by reader() and
writer() may block in multithreaded scenarios.
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");
}