I am running a springboot server.
This server has some webservices.
One of those services has to run an external jar when it receives a request. Actually the server is the interface between a calculation engine (the jar), and the user.
There is the code :
public class Launcher extends Thread{
#Override
public void run() {
// TODO Auto-generated method stub
runJar(this.getJar(), this.getArgs());
}
private void runJar(String jar, String[] args){
try {
String[] s = new String[4+args.length];
s[0] = "nohup";
s[1] = "java";
s[2] = "-jar";
s[3] = jar;
for(int i = 0; i < args.length; i++){
s[i+4] = args[i];
}
Process p = Runtime.getRuntime().exec(s);
//Process exec = Runtime.getRuntime().exec(new String[] {"mkdir", "monTest"});
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("failed");
e.printStackTrace();
}
}
}
public class Memory {
private ArrayList<Integer> startedIds;
public ArrayList<Integer> getStartedIds() {
return startedIds;
}
public void setStartedIds(ArrayList<Integer> startedIds) {
this.startedIds = startedIds;
}
public Memory() {
this.startedIds = new ArrayList<>();
}
public Memory(ArrayList<Integer> arr) {
this.startedIds = arr;
}
public int start() {
int id = this.findAvailableId();
this.getStartedIds().add(id);
System.out.println("i'm going to start with a big command!+uhpop");
String[] args = {"arg1","arg2", "arg3", "&"};
Launcher launcher = new Launcher("myJar.jar", args);
launcher.start();
return id;
}
private int findAvailableId() {
int id = 0;
while(this.getStartedIds().contains(id)){
id++;
}
return id;
}
}
If my jar do something really simple such as create a file, it works nice. But if it's more complex, the thread just stops working, the cpu fall to 0%. It depends on what i ask. For some task it can run 30-35seconds before the issue happens for others such as doing
while(true);
It stopped a few seconds latter.
I thought it was something like a timeout, but actually it is not a constant time. Maybe something like memory issue...?
I have tried to run the same code outside the springboot server (on a simple java project main that launch Memory.start() and it works well. So I supposed it was a spring boot misunderstanding from my side. If someone know how to make this jar run independently from the springboot server just tell me please.
Thank you.
I finally found the solution. I had to place a
p.waitFor();
so the thread launching the jar will not stop. Then, the input and the output of the jar are not connected to the input/output of the lauching thread, then, i had to create an other thread to monitor the output of the jar (it actually print it in the main thread). I found those informations here : http://labs.excilys.com/2012/06/26/runtime-exec-pour-les-nuls-et-processbuilder/
I still don't really understand why it was working outside the springboot server, actually it should not have run...
If somebody is interested, here is my code.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
class AfficheurFlux implements Runnable {
private final InputStream inputStream;
AfficheurFlux(InputStream inputStream) {
this.inputStream = inputStream;
}
private BufferedReader getBufferedReader(InputStream is) {
return new BufferedReader(new InputStreamReader(is));
}
#Override
public void run() {
BufferedReader br = getBufferedReader(inputStream);
String ligne = "";
try {
while ((ligne = br.readLine()) != null) {
System.out.println(ligne);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class Memory {
private ArrayList<Integer> startedIds;
public ArrayList<Integer> getStartedIds() {
return startedIds;
}
public void setStartedIds(ArrayList<Integer> startedIds) {
this.startedIds = startedIds;
}
public Memory() {
this.startedIds = new ArrayList<>();
}
public Memory(ArrayList<Integer> arr) {
this.startedIds = arr;
}
public int startJar() {
int id = this.findAvailableId();
this.getStartedIds().add(id);
System.out.println("i'm going to start with a big command!");
String[] args = {"arg1","arg2", "arg3"};
Launcher launcher = new Launcher("myJar.jar", args);
launcher.start();
return id;
}
private int findAvailableId() {
int id = 0;
while(this.getStartedIds().contains(id)){
id++;
}
return id;
}
public class Launcher extends Thread{
private String jar;
private String[] args;
public AntLauncher(String jar, String[] args) {
super();
this.jar = jar;
this.args = args;
}
#Override
public void run() {
runJar(this.getJar(), this.getArgs());
}
private void runJar(String jar, String[] args){
try {
String[] s = new String[3+args.length];
s[0] = "java";
s[1] = "-jar";
s[2] = jar;
for(int i = 0; i < args.length; i++){
s[i+3] = args[i];
}
Process p = Runtime.getRuntime().exec(s);
AfficheurFlux fluxSortie = new AfficheurFlux(p.getInputStream());
AfficheurFlux fluxErreur = new AfficheurFlux(p.getErrorStream());
new Thread(fluxSortie).start();
new Thread(fluxErreur).start();
p.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Fin du programme");
}
}
}
Related
I'm trying to get data from four different sources with four scanners. I do realize that I need to use threads. But here's the error message:
P.S = paths for the files were fine before using thread. ( I was using one file, path was ok.)
null
null
null
null
java.lang.ArrayIndexOutOfBoundsException: 41705
at getText.getCities(getText.java:132)
at getText$1.run(getText.java:23)
at java.lang.Thread.run(Unknown Source)
java.lang.ArrayIndexOutOfBoundsException: 41705
at getText.getNames(getText.java:112)
at getText$2.run(getText.java:30)
at java.lang.Thread.run(Unknown Source)
Code Itself
public class getText {
static int ln = 41705;
static String [] icaos = new String[ln];
static String [] iatas = new String[ln];
static String [] names = new String[ln];
static String [] cities = new String[ln];
public final Runnable typeA;
public final Runnable typeB;
public final Runnable typeC;
public final Runnable typeD;
public getText() {
typeA = new Runnable() {
public void run() {
getText.this.getCities();
}
};
typeB = new Runnable() {
public void run() {
getText.this.getNames();
}
};
typeC = new Runnable() {
public void run() {
getText.this.getIcao();
}
};
typeD = new Runnable() {
public void run() {
getText.this.getIata();
}
};
}
public static void main(String[] args) {
// TODO Auto-generated method stub
getText x = new getText();
new Thread(x.typeA).start();
new Thread(x.typeB).start();
new Thread(x.typeC).start();
new Thread(x.typeD).start();
System.out.println(icaos[32541]);
System.out.println(iatas[32541]);
System.out.println(names[32541]);
System.out.println(cities[32541]);
}
public void getIcao () {
try {
int i=0;
InputStream icao_stream = new FileInputStream("src/icao.txt");
Scanner icao_s = new Scanner(icao_stream);
icao_s.useDelimiter(",");
while(icao_s.hasNext()) {
icaos[i] = icao_s.next();
i++;
}
icao_s.close();
icao_stream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void getIata() {
try {
int i=0;
InputStream iata_stream = new FileInputStream("src/iata.txt");
Scanner iata_s = new Scanner(iata_stream);
iata_s.useDelimiter(",");
while(iata_s.hasNext()) {
iatas[i] = iata_s.next();
i++;
}
iata_s.close();
iata_stream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void getNames() {
try {
int i=0;
InputStream names_stream = new FileInputStream("src/names.txt");
Scanner names_s = new Scanner(names_stream);
names_s.useDelimiter(",");
while(names_s.hasNext()) {
names[i] = names_s.next();
i++;
}
names_s.close();
names_stream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void getCities() {
try {
int i=0;
InputStream cities_stream = new FileInputStream("src/cities.txt");
Scanner cities_s = new Scanner(cities_stream);
cities_s.useDelimiter(",");
while(cities_s.hasNext()) {
cities[i] = cities_s.next();
i++;
}
cities_s.close();
cities_stream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
So the problem now is you have started your threads, but the control returns immediately to the main thread and your other threads are not finished working by then. What you need is to wait for those threads to finish working and then check for results. There are multiple ways to achieve that. A simple one is to change your main to:
public static void main(String[] args) {
getText x = new getText();
List<Thread> threads = new ArrayList<>();
threads.add(new Thread(x.typeA));
threads.add(new Thread(x.typeB));
threads.add(new Thread(x.typeC));
threads.add(new Thread(x.typeD));
threads.forEach(t -> t.start());
threads.forEach(t -> {
try {
//this makes the main thread to wait for thread "t" to finish
t.join();
} catch (InterruptedException e) {
// log or throw or anything you need to do
}
});
System.out.println(icaos[32541]);
System.out.println(iatas[32541]);
System.out.println(names[32541]);
System.out.println(cities[32541]);
}
This is not the most optimal solution but the simplest one. Others better options would be to use a CyclicBarrier or ExecutorService among others.
I am reading two text files concurrently line by line.
What I am specifically want to do is when the lineCount on each thread are the same I want to take a look at the string that the scanner is currently reading.
I looked around for certain pattern I can implement like Compare and Swap and Slipped Condition but I cannot wrap my head around how it would help me achieve my goal. I am new to concurrency programming.
What I have managed so far is to synchronize the string reading and printing with counterSync method and I know that I have carry out my thread lock/pause operation there and take a look at the string.
public class concurrencyTest {
public static void main(String[] args) throws IOException {
String filePath1 = "path1.txt";
String filePath2 = "path2.txt";
reader reader = new reader();
MyThread source = new MyThread(reader, filePath1);
MyThread target = new MyThread(reader, filePath2);
source.start();
target.start();
}
static public class reader {
void read(String filePath) throws IOException {
readFile(filePath);
}
}
static synchronized void counterSync(String thread) {
System.out.println(thread);
}
static class MyThread extends Thread {
reader reader;
String filePath;
MyThread(reader reader, String filePath) {
this.reader = reader;
this.filePath = filePath;
}
#Override
public void run() {
try {
reader.read(filePath);
} catch (IOException e) {
e.printStackTrace();
}
}
}
static void readFile(String filePath) throws IOException {
FileInputStream inputStream = null;
Scanner sc = null;
int lineCount = 0;
try {
inputStream = new FileInputStream(filePath);
sc = new Scanner(inputStream, "UTF-8");
while (sc.hasNextLine()) {
lineCount++;
System.out.println(lineCount + "===" + sc.nextLine());
counterSync(sc.nextLine());
}
if (sc.ioException() != null) {
throw sc.ioException();
}
} finally {
if (inputStream != null) {
inputStream.close();
}
if (sc != null) {
sc.close();
}
}
}
}
Ok, what you are looking for is a little bit complex but still possible.
Your question lacks of some examples so correct me if I'm wrong in something.
You have 2 threads:
thread1
thread2
and 2 files:
file1
file2
Content of file1:
file1
file2
file3
file4
file5
file6
file7
file8
file9
Content of file2:
file11
file22
file33
file44
file55
file66
file77
file88
file99
You want to stop all threads on the same line numbers and do some oeration with the output.
This is the thread implementation for reading the files, we will instantiate 2 instance of it, each instance will manage a file.
static class ReaderThread extends Thread {
private File fileToRead;
public final Object lock = new Object();
private String currentLine;
private AtomicInteger lineCount = new AtomicInteger(0);
public ReaderThread(File fileToRead) {
this.fileToRead = fileToRead;
}
#Override
public void run() {
synchronized (lock) {
try {
Stream<String> lines = Files.lines(Path.of(fileToRead.getPath()));
lines.forEach(line -> {
currentLine = line;
// Here's your logic on different lines
if (lineCount.get() == 4 || lineCount.get() == 5 || lineCount.get() == 6) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lineCount.getAndIncrement();
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
public String getCurrentLine() {
return currentLine;
}
public boolean isLocked() {
return getState().equals(State.WAITING);
}
}
Then we will use an helper thread to notify the reader threads when our elboration will be ok:
static class HelperThread extends Thread {
private List<ReaderThread> threads;
#Override
public void run() {
while (true) {
if (threads.stream().allMatch(ReaderThread::isLocked)) {
System.out.println("next line:");
threads.forEach(thread -> {
synchronized (thread.lock) {
System.out.println(thread.getCurrentLine());
thread.lock.notify();
}
});
System.out.println("\n");
}
}
}
public HelperThread(List<ReaderThread> threads) {
this.threads = threads;
}
}
Finally the main class for testing all:
public static void main(String[] args) {
File f1 = new File(Objects.requireNonNull(Main.class.getClassLoader().getResource("file1.txt")).getFile());
File f2 = new File(Objects.requireNonNull(Main.class.getClassLoader().getResource("file2.txt")).getFile());
ReaderThread t1 = new ReaderThread(f1);
ReaderThread t2 = new ReaderThread(f2);
HelperThread helperThread = new HelperThread(List.of(t1, t2));
helperThread.start();
t1.start();
t2.start();
}
Executing the program will result in this output:
next line:
file5
file55
next line:
file6
file66
next line:
file7
file77
Here's the complete list of imports:
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
Please note: this is a rude example, you need to manage with the correct shutdown of the threads, some modifiers are public so encapsulate it following the java guidelines, coorrectly manage all exceptions and do some general refactor.
If you want a more versatile implementation, to interpolate different lines, the following should be ok:
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
public class Main2 {
public static void main(String[] args) {
File f1 = new File(Objects.requireNonNull(Main2.class.getClassLoader().getResource("file1.txt")).getFile());
File f2 = new File(Objects.requireNonNull(Main2.class.getClassLoader().getResource("file2.txt")).getFile());
ReaderThread t1 = new ReaderThread(f1);
ReaderThread t2 = new ReaderThread(f2);
HelperThread helperThread = new HelperThread(List.of(t1, t2));
helperThread.start();
t1.setName("Reader1");
t1.setName("Reader2");
t1.start();
t2.start();
}
static class ReaderThread extends Thread {
private final File fileToRead;
private final Object lock = new Object();
private final AtomicInteger lineCount = new AtomicInteger(0);
private String currentLine;
public ReaderThread(File fileToRead) {
this.fileToRead = fileToRead;
}
#Override
public void run() {
synchronized (lock) {
try {
Stream<String> lines = Files.lines(Path.of(fileToRead.getPath()));
lines.forEach(line -> {
currentLine = line;
lineCount.getAndIncrement();
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void lock() throws InterruptedException {
this.lock.wait();
}
public void unlock() {
this.lock.notify();
}
public boolean isLocked() {
return getState().equals(State.WAITING);
}
public Object getLock() {
return lock;
}
public AtomicInteger getLineCount() {
return lineCount;
}
public String getCurrentLine() {
return currentLine;
}
}
static class HelperThread extends Thread {
private List<ReaderThread> threads;
#Override
public void run() {
while (true) {
threads.forEach(t -> {
try {
if (t.getName().equals("Reader1") && t.getLineCount().get() == 3) t.lock();
if (t.getName().equals("Reader2") && t.getLineCount().get() == 4) t.lock();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
if (threads.stream().allMatch(ReaderThread::isLocked)) {
System.out.println("next line:");
threads.forEach(t -> {
synchronized (t.getLock()) {
System.out.println(t.getCurrentLine());
t.unlock();
}
});
System.out.println("\n");
}
}
}
public HelperThread(List<ReaderThread> threads) {
this.threads = threads;
}
}
}
Be sure that the HelperThread starts before the other threads or it's possible to loose some data.
It seems that you didn't post a complete example. But, a few general comments:
You might be able to get away with using "compare-and-swap" logic for an integer, but you should not expect it to work for a more-sophisticated thing like a Java "String" or any sort of container.
You should simply use the synchronization-objects provided in the language. If you are going to update or even to examine a shared data structure, you must be holding the proper lock.
Of course, "thread-safe queues" are very helpful in many designs because they facilitate the most-common activity – message-passing – and allow the various threads to operate graciously at slightly-varying speeds. You still have to lock anything that's shared, but nonetheless it's a useful design that's really as old as the Unix® "pipe."
You can use
java.util.concurrent.CyclicBarrier
A synchronization aid that allows a set of threads to all wait for
each other to reach a common barrier point. CyclicBarriers are useful
in programs involving a fixed sized party of threads that must
occasionally wait for each other. The barrier is called cyclic because
it can be re-used after the waiting threads are released.
A CyclicBarrier supports an optional Runnable command that is run once
per barrier point, after the last thread in the party arrives, but
before any threads are released. This barrier action is useful for
updating shared-state before any of the parties continue.
Here is an example using this class:
public static void main(String[] args) throws IOException {
String filePath1 = "path1.txt";
String filePath2 = "path2.txt";
ReaderThread reader1 = new ReaderThread(filePath1);
ReaderThread reader2 = new ReaderThread(filePath2);
CyclicBarrier cyclicBarrier = new CyclicBarrier(2, () -> {
//processing when condition met in both thread
List<String> lines1 = reader1.getLines();
List<String> lines2 = reader2.getLines();
System.out.println(lines1.get(lines1.size() - 1) + " " + lines2.get(lines2.size()-1));
});
reader1.setCyclicBarrier(cyclicBarrier);
reader2.setCyclicBarrier(cyclicBarrier);
reader1.start();
reader2.start();
}
public static class ReaderThread extends Thread {
CyclicBarrier cyclicBarrier;
String file;
List<String> lines = new ArrayList<>();
public void setCyclicBarrier(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
public ReaderThread(String file) {
this.file = file;
}
#Override
public void run() {
try (BufferedReader reader = Files.newBufferedReader(Paths.get(file))) {
String line = null;
for (int i = 0; (line = reader.readLine()) != null; i++) {
lines.add(line);
//condition do something
if (i % 10 == 0) {
cyclicBarrier.await();
}
}
} catch (IOException | InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
public List<String> getLines() {
return new ArrayList<>(lines);
}
}
And output:
this is from file1 1232123321312 this is from file 2 1232123321312
this is from file1 1232123321312 this is from file 2 1232123321312
this is from file1 1232123321312 this is from file 2 1232123321312
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 6 years ago.
I'm pretty new to this whole "Sockets" and networking world.
First, I wanted to make a random chat program like "omegle" and it worked perfectly fine. I think I had some serious issues in the code, but it worked - so why bother? (I wish I did).
Now I am adding a "Multiplayer" option in my "Tic Tac Toe" game in android, it went wrong and I spent many hours figuring how to solve this problem but nothing worked, my app just kept crashing.
Here's the code for the simple chat program.
Server
public class server {
public static Map<Integer, MiniServer> clients;
public static void main(String args[]) throws IOException {
clients = new HashMap<>();
boolean listeningSocket = true;
ServerSocket serverSocket = new ServerSocket(1234);
while (listeningSocket) {
Socket socket = serverSocket.accept();
MiniServer mini = new MiniServer(socket);
if (clients.isEmpty()) {
clients.put(1, mini);
mini.setId(1);
} else {
int i = 1;
while (clients.containsKey(i))
i++;
clients.put(i, mini);
mini.setId(i);
}
mini.start();
}
serverSocket.close();
}
Client
public class client {
private static String message;
private static boolean connected;
private static boolean connectedInternet;
public static void main(String args[]) throws UnknownHostException, IOException {
Scanner textReader = new Scanner(System.in);
Socket socket = new Socket("127.0.0.1", 1234);
Scanner inputStreamReader = new Scanner(socket.getInputStream());
connectedInternet = true;
System.out.println("Hello Stranger, get ready to chat.");
PrintStream printStream = new PrintStream(socket.getOutputStream());
Thread getMessage = new Thread() {
public void run() {
while (true) {
message = textReader.nextLine();
if (!connected)
System.out.println("You are not connected to another Stranger yet, please wait.");
else
printStream.println(message);
}
}
};
getMessage.start();
while (connectedInternet) {
String temp = inputStreamReader.nextLine();
if (temp.equals("connected")) {
connected = true;
System.out.println("Found a Stranger, say hey !");
} else if (connected) {
if (temp.equals("!close")) {
System.out.println("Stranger disconnected.");
printStream.println("!new");
} else
System.out.println("Stranger: " + temp);
}
}
textReader.close();
socket.close();
inputStreamReader.close();
}
MiniServer
public class MiniServer extends Thread {
private Socket socket = null;
public int id;
private boolean foundPlayer;
private int colleague;
private boolean connected;
public MiniServer(Socket socket) {
super("MiniServer");
this.socket = socket;
}
public void run() {
Scanner inputStreamReader = null;
String message;
try {
inputStreamReader = new Scanner(socket.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
PrintStream p = null;
try {
p = new PrintStream(socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
List<Integer> keys = new ArrayList<Integer>(server.clients.keySet());
while (!foundPlayer) {
for (Integer key : keys) {
if (!server.clients.get(key).foundPlayer && key != id) {
server.clients.get(key).foundPlayer = true;
foundPlayer = true;
server.clients.get(key).colleague = id;
colleague = server.clients.get(key).id;
}
}
try {
keys = new ArrayList<Integer>(server.clients.keySet());
} catch (ConcurrentModificationException e) {
}
}
p.println("connected");
connected = true;
while (connected) {
try {
message = inputStreamReader.nextLine();
if (message.equals("!new")) {
foundPlayer = false;
keys = new ArrayList<Integer>(server.clients.keySet());
while (!foundPlayer) {
for (Integer key : keys) {
if (!server.clients.get(key).foundPlayer && key != id) {
server.clients.get(key).foundPlayer = true;
foundPlayer = true;
server.clients.get(key).colleague = id;
colleague = server.clients.get(key).id;
}
}
try {
keys = new ArrayList<Integer>(server.clients.keySet());
} catch (ConcurrentModificationException e) {
}
}
p.println("connected");
} else
sendToClient(message);
} catch (NoSuchElementException e) {
server.clients.remove(id);
sendToClient("!close");
closeSocket();
connected = false;
}
}
}
public void setId(int i) {
id = i;
}
public void sendToClient(String message) {
Socket colleagueSocket = server.clients.get(colleague).socket;
PrintStream rr = null;
try {
rr = new PrintStream(colleagueSocket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
rr.println(message);
}
public void closeSocket() {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
This program works great, but I'm pretty sure there are tons of problems with it.
Now here's my Server-side code for my android application.
Server
public class Server {
public static Map<Integer, MiniServer> clients;
public static void main(String args[]) throws IOException {
clients = new HashMap<>();
boolean listeningSocket = true;
ServerSocket serverSocket = new ServerSocket(1234);
while (listeningSocket) {
Socket socket = serverSocket.accept();
MiniServer mini = new MiniServer(socket);
if (clients.isEmpty()) {
clients.put(1, mini);
mini.setId(1);
} else {
int i = 1;
while (clients.containsKey(i))
i++;
clients.put(i, mini);
mini.setId(i);
}
mini.start();
}
serverSocket.close();
}
Mini Server
public class MiniServer extends Thread {
private Socket socket;
private Socket colleagueSocket;
public int id;
private boolean foundPlayer;
private int colleague;
private boolean connected;
private String crossOrCircle;
private boolean thisGoes;
private Thread timeOut;
private PrintStream p;
private Timer timer;
public MiniServer(Socket socket) {
super("MiniServer");
this.socket = socket;
}
public void run() {
Scanner inputStreamReader = null;
String message;
try {
inputStreamReader = new Scanner(socket.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
try {
p = new PrintStream(socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
List<Integer> keys = new ArrayList<Integer>(Server.clients.keySet());
while (!foundPlayer) {
for (Integer key : keys) {
if (!Server.clients.get(key).foundPlayer && key != id) {
Server.clients.get(key).foundPlayer = true;
foundPlayer = true;
Server.clients.get(key).colleague = id;
colleague = Server.clients.get(key).id;
crossOrCircle = "X";
Server.clients.get(key).crossOrCircle = "O";
thisGoes = true;
Server.clients.get(key).thisGoes = false;
colleagueSocket=Server.clients.get(key).colleagueSocket;
Server.clients.get(key).colleagueSocket=socket;
}
}
try {
keys = new ArrayList<Integer>(Server.clients.keySet());
} catch (ConcurrentModificationException e) {
}
}
p.println("connected");
connected = true;
p.println(crossOrCircle);
while (connected) {
try {
message = inputStreamReader.nextLine();
if (Character.toString(message.charAt(0)).equals(crossOrCircle) && thisGoes) {
p.println(message);
sendToClient(message);
thisGoes = false;
Server.clients.get(colleague).thisGoes = true;
} else if (message.equals("!close")) {
sendToClient("!closeClient");
p.println("!closeClient");
Server.clients.get(colleague).connected = false;
connected = false;
Server.clients.get(colleague).closeSocket();
closeSocket();
Server.clients.remove(colleague);
Server.clients.remove(id);
} else if (message.equals("!pause")) {
timeOut = new Thread() {
#Override
public void run() {
timer = new Timer();
timer.schedule(
new TimerTask() {
#Override
public void run() {
sendToClient("!closeClient");
p.println("!closeClient");
Server.clients.get(colleague).connected = false;
connected = false;
Server.clients.get(colleague).closeSocket();
closeSocket();
Server.clients.remove(colleague);
Server.clients.remove(id);
}
},
5000
);
}
};
timeOut.start();
} else if (message.equals("!resume")) {
timer.cancel();
}
} catch (NoSuchElementException e) {
sendToClient("!closeClient");
p.println("!closeClient");
Server.clients.get(colleague).connected = false;
connected = false;
Server.clients.get(colleague).closeSocket();
closeSocket();
Server.clients.remove(colleague);
Server.clients.remove(id);
}
}
}
public void setId(int i) {
id = i;
}
public void sendToClient(String message) {
PrintStream rr = null;
try {
rr = new PrintStream(colleagueSocket.getOutputStream());
} catch (IOException | NullPointerException e) {
e.printStackTrace();
}
rr.println(message);
}
public void closeSocket() {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public Socket getSocket(){
return this.socket;
}
There's a problem in the sendClient() method, it keeps throwing NullPointerException.
What can I do? I'm not asking you to solve my problem.
Could you give me some advices please?
Thank you very much :)
Edit:
I forgot to mention some thing- I'm running the server on my computer and I'm using two different devices that are connected to the LAN.
java.lang.NullPointerException
at com.ilya.rabinovich.tictactoe.MiniServer.sendToClient(MiniServer.java:134)
at com.ilya.rabinovich.tictactoe.MiniServer.run(MiniServer.java:75)
Exception in thread "MiniServer" java.lang.NullPointerException
at com.ilya.rabinovich.tictactoe.MiniServer.sendToClient(MiniServer.java:138)
at com.ilya.rabinovich.tictactoe.MiniServer.run(MiniServer.java:75)
Edit 2:
I fixed this exception by changing this line
colleagueSocket=Server.clients.get(key).colleagueSocket;
To
colleagueSocket=Server.clients.get(key).socket;
When running this app on the android emulators (android studio) it works perfectly fine, but when I try running this app on external devices (Lg g3 and nexus 7) it works really weird and crashes most of the times.
Edit 3:
Okay I solved the problem =)
The problem was in the client(runOnUiThread).
Anyways, do you think there are ways to improve my Server code? Thanks !
I don't know if you already did, but you need to whitelist the server ip in your config.xml file.
This might be one one reason.
A very good article (When Runtime.exec() won't) says: The only possible time you would use exitValue() instead of waitFor() would be when you don't want your program to block waiting on an external process that may never complete. Instead of using the waitFor() method, I would prefer passing a boolean parameter called waitFor into the exitValue() method to determine whether or not the current thread should wait. A boolean would be more beneficial because exitValue() is a more appropriate name for this method, and it isn't necessary for two methods to perform the same function under different conditions. Such simple condition discrimination is the domain of an input parameter.
I have exactly same situation where my system call would start a process which will keep running until user decides to kill it. If I use '(process.waitFor() == 0)' it will block program there because process will not be completed. Author in article above suggest that exitValue() can be used with 'waitFor' parameter. Did anybody try it out ? Any example would be helpful.
Code:
// Start ProcessBuilder, 'str' contains a command
ProcessBuilder pbuilder = new ProcessBuilder(str);
pbuilder.directory(new File("/root/workspace/Project1"));
pbuilder.redirectErrorStream(true);
Process prcs = pbuilder.start();
AForm.execStatustext.append("\n=> Process is:" + prcs);
// Read output
StringBuilder out = new StringBuilder();
BufferedReader bfrd = new BufferedReader(new InputStreamReader(process.getInputStream()));
String current_line = null, previous_line = null;
while ((current_line = bfrd.readLine()) != null) {
if (!line.equals(previous_line)) {
previous_line = current_line;
out.append(current_line).append('\n');
//System.out.println(line);
}
}
//process.getInputStream().close();
// Send 'Enter' keystroke through BufferedWriter to get control back
BufferedWriter bfrout = new BufferedWriter(new OutputStreamWriter(prcs.getOutputStream()));
bfrout.write("\\r");
bfrout.newLine();
bfrout.flush();
bfrout.write("\\r");
bfrout.newLine();
bfrout.flush();
//process.getOutputStream().close();*/
if (prcs.waitFor() == 0)
System.out.println("Commands executed successfully");
System.exit(0);
This is a "rough" example of some library code I use to launch external processes.
Basically, this uses three threads. The first is used to execute the actually command and then wait till it exists.
The other two deal with the processes output and input streams. This makes these independent of each other prevents the ability for one to block the other.
The whole thing is then tied together with a listener that is notified when something happens.
The error handling could be better (as the fail condition is a little unclear as to what/who actually failed), but the basic concept is there...
This means you can launch the process and not care...(until you want to)
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class TestBackgroundProcess {
public static void main(String[] args) {
new TestBackgroundProcess();
}
public TestBackgroundProcess() {
BackgroundProcess bp = new BackgroundProcess("java", "-jar", "dist/BackgroundProcess.jar");
bp.setListener(new ProcessListener() {
#Override
public void charRead(BackgroundProcess process, char value) {
}
#Override
public void lineRead(BackgroundProcess process, String text) {
System.out.println(text);
}
#Override
public void processFailed(BackgroundProcess process, Exception exp) {
System.out.println("Failed...");
exp.printStackTrace();
}
#Override
public void processCompleted(BackgroundProcess process) {
System.out.println("Completed - " + process.getExitValue());
}
});
System.out.println("Execute command...");
bp.start();
bp.send("dir");
bp.send("exit");
System.out.println("I'm not waiting here...");
}
public interface ProcessListener {
public void charRead(BackgroundProcess process, char value);
public void lineRead(BackgroundProcess process, String text);
public void processFailed(BackgroundProcess process, Exception exp);
public void processCompleted(BackgroundProcess process);
}
public class BackgroundProcess extends Thread {
private List<String> commands;
private File startIn;
private int exitValue;
private ProcessListener listener;
private OutputQueue outputQueue;
public BackgroundProcess(String... cmds) {
commands = new ArrayList<>(Arrays.asList(cmds));
outputQueue = new OutputQueue(this);
}
public void setStartIn(File startIn) {
this.startIn = startIn;
}
public File getStartIn() {
return startIn;
}
public int getExitValue() {
return exitValue;
}
public void setListener(ProcessListener listener) {
this.listener = listener;
}
public ProcessListener getListener() {
return listener;
}
#Override
public void run() {
ProcessBuilder pb = new ProcessBuilder(commands);
File startIn = getStartIn();
if (startIn != null) {
pb.directory(startIn);
}
pb.redirectError();
Process p;
try {
p = pb.start();
InputStreamConsumer isc = new InputStreamConsumer(p.getInputStream(), this, getListener());
outputQueue.init(p.getOutputStream(), getListener());
outputQueue.start();
p.waitFor();
isc.join();
outputQueue.terminate();
outputQueue.join();
ProcessListener listener = getListener();
if (listener != null) {
listener.processCompleted(this);
}
} catch (InterruptedException ex) {
ProcessListener listener = getListener();
if (listener != null) {
listener.processFailed(this, ex);
}
} catch (IOException ex) {
ProcessListener listener = getListener();
if (listener != null) {
listener.processFailed(this, ex);
}
}
}
public void send(String cmd) {
outputQueue.send(cmd);
}
}
public class OutputQueue extends Thread {
private List<String> cmds;
private OutputStream os;
private ProcessListener listener;
private BackgroundProcess backgroundProcess;
private ReentrantLock waitLock;
private Condition waitCon;
private boolean keepRunning = true;
public OutputQueue(BackgroundProcess bp) {
backgroundProcess = bp;
cmds = new ArrayList<>(25);
waitLock = new ReentrantLock();
waitCon = waitLock.newCondition();
}
public ProcessListener getListener() {
return listener;
}
public OutputStream getOutputStream() {
return os;
}
public BackgroundProcess getBackgroundProcess() {
return backgroundProcess;
}
public void init(OutputStream outputStream, ProcessListener listener) {
os = outputStream;
this.listener = listener;
}
public void send(String cmd) {
waitLock.lock();
try {
cmds.add(cmd);
waitCon.signalAll();
} finally {
waitLock.unlock();
}
}
public void terminate() {
waitLock.lock();
try {
cmds.clear();
keepRunning = false;
waitCon.signalAll();
} finally {
waitLock.unlock();
}
}
#Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
}
BackgroundProcess backgroundProcess = getBackgroundProcess();
ProcessListener listener = getListener();
OutputStream outputStream = getOutputStream();
try {
while (keepRunning) {
while (cmds.isEmpty() && keepRunning) {
waitLock.lock();
try {
waitCon.await();
} catch (Exception exp) {
} finally {
waitLock.unlock();
}
}
if (!cmds.isEmpty()) {
waitLock.lock();
try {
while (!cmds.isEmpty()) {
String cmd = cmds.remove(0);
System.out.println("Send " + cmd);
outputStream.write(cmd.getBytes());
outputStream.write('\n');
outputStream.write('\r');
outputStream.flush();
}
} finally {
waitLock.unlock();
}
}
}
} catch (IOException ex) {
if (listener != null) {
listener.processFailed(backgroundProcess, ex);
}
}
}
}
public class InputStreamConsumer extends Thread {
private InputStream is;
private ProcessListener listener;
private BackgroundProcess backgroundProcess;
public InputStreamConsumer(InputStream is, BackgroundProcess backgroundProcess, ProcessListener listener) {
this.is = is;
this.listener = listener;
this.backgroundProcess = backgroundProcess;
start();
}
public ProcessListener getListener() {
return listener;
}
public BackgroundProcess getBackgroundProcess() {
return backgroundProcess;
}
#Override
public void run() {
BackgroundProcess backgroundProcess = getBackgroundProcess();
ProcessListener listener = getListener();
try {
StringBuilder sb = new StringBuilder(64);
int in = -1;
while ((in = is.read()) != -1) {
char value = (char) in;
if (listener != null) {
listener.charRead(backgroundProcess, value);
if (value == '\n' || value == '\r') {
if (sb.length() > 0) {
listener.lineRead(null, sb.toString());
sb.delete(0, sb.length());
}
} else {
sb.append(value);
}
}
}
} catch (IOException ex) {
listener.processFailed(backgroundProcess, ex);
}
}
}
}
Before using waitFor in main thread, create another thread (child) and construct logic for your termination cases in this new thread. For example, wait for 10 secs.
If the condition is fulfilled, then interrupt the main thread from the child thread ant handle the following logic on your main thread.
The following code creates a child thread to invoke the process and the main thread does its work until the child finishes successfully.
import java.io.IOException;
public class TestExecution {
public boolean myProcessState = false;
class MyProcess implements Runnable {
public void run() {
//------
Process process;
try {
process = Runtime.getRuntime().exec("your command");
process.waitFor();
int processExitValue = process.exitValue();
if(processExitValue == 0) {
myProcessState = true;
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void doMyWork() {
MyProcess myProcess = new MyProcess();
Thread myProcessExecuter = new Thread(myProcess);
myProcessExecuter.start();
while(!myProcessState) {
// do your job until the process exits with success
}
}
public static void main(String[] args) {
TestExecution testExecution = new TestExecution();
testExecution.doMyWork();
}
}
If I use '(process.waitFor() == 0)' it will block program there because process will not be completed.
No it won't. It will block the thread. That's why you have threads.
Author in article above suggest that exitValue() can be used with 'waitFor' parameter
No he doesn't. He is talking about how he would have designed it, if anybody had asked him. But they didn't, and he didn't.
Did anybody try it out ?
You can't. It doesn't exist.
I've a batch file that needs to be invoked from a java program. The batch file in-turn invokes an EXE. The EXE program will return data which I want to handle. If the EXE prints data to console am able to capture it as follows. But when the EXE is returning data after its completion, am not able to capture it.
ProcessBuilder pb = new ProcessBuilder("foo.bat");
Process p = pb.start();
int exitValue = p.waitFor();
BufferedReader reader;
// System.out.println("Exit Value" + exitValue);
if (exitValue == 0) {
reader = new BufferedReader(new InputStreamReader(p
.getInputStream()));
} else {
reader = new BufferedReader(new InputStreamReader(p
.getErrorStream()));
}
StringBuffer sb = new StringBuffer();
String temp = reader.readLine();
while (temp != null) {
sb.append(temp);
temp = reader.readLine();
}
reader.close();
System.out.println(sb.toString());
How do i need to capture the data returned by the EXE executed from a batch file?
The EXE is basically a C program. When I invoke the C program, the main method returns me the data, which I want to handle it.
Do you have control over the script? I'd try storing the return value (that's what you want?) from the executable to an environment variable. You may have to export it. Here's a tutorial on how to handle environment variables with Java.
Thanks to jitters comment - no, it doesn't work. We can't change values of the environment variable in a 'global' way (now I know..)
But, the idea works with a little adaptation: I'd still try to store the return value in a global accessible resource: Simply send the return value to a file (exec myapp > result.txt) and read the value from that file in your java application.
I think i had the same problem some time ago. One problem with the previous strategy is that you're waiting for the process to finish (waitFor) to capture the data returned from it. You may have problems if the process fails or hang ups. A better aproach would be something like this:
You should create two threads to consume the input stream and the error stream of the process, independently of the waitFor call. Something like these should work:
1.- Create a class that wraps the execution of the process:
public class ExecutionWrapper {
private int exitStatus;
private String[] command;
private String[] environment;
private String directory;
private boolean running;
private Process process;
private ExecutionWrapperOutput error;
private ExecutionWrapperOutput output;
public ExecutionWrapper(String command, String[] environment, String directory) {
this.command = new String[] { command };
this.environment = environment;
this.directory = directory;
this.exitStatus = -1;
}
public ExecutionWrapper(List<String> command, List<String> environment, String directory) {
if (command != null)
this.command = command.toArray(new String[command.size()]);
if (environment != null)
this.environment = environment.toArray(new String[environment.size()]);
this.directory = directory;
this.exitStatus = -1;
}
public void start() {
try {
this.process = Runtime.getRuntime().exec(this.command, this.environment, new File(this.directory));
this.running = true;
// Error and information messages
this.error = new ExecutionWrapperOutput(this.process.getErrorStream());
this.output = new ExecutionWrapperOutput(this.process.getInputStream());
// Start the messaging threads
this.error.start();
this.output.start();
// Final status
Runnable runner = new Runnable() {
public void run() {
try {
ExecutionWrapper.this.exitStatus = ExecutionWrapper.this.process.waitFor();
ExecutionWrapper.this.running = false;
ExecutionWrapper.this.process.destroy();
} catch (Exception ex) {
LoggingUtiles.exception(ex);
ExecutionWrapper.this.exitStatus = -1;
}
}
};
new Thread(runner).start();
} catch (Throwable t) {
LoggingUtiles.exception(t);
}
}
public void stop() {
this.running = false;
this.process.destroy();
}
public boolean isRunning() {
return running;
}
public int getExitStatus() {
return exitStatus;
}
public String[] getError(boolean clear) {
return this.error.getLines(clear);
}
public String[] getOutput(boolean clear) {
return this.output.getLines(clear);
}
public String[] getCommand() {
return command;
}
public String getDirectory() {
return directory;
}
public void waitFor() {
try {
process.waitFor();
} catch (Throwable t) {
LoggingUtiles.exception(t);
}
}
}
2.- Then, create the ExecutionWrapperOutput class, that processes the output of the process streams:
public class ExecutionWrapperOutput extends Thread {
private InputStream is;
private List<String> output;
private Object mutex = new Object();
ExecutionWrapperOutput(InputStream is) {
this.is = is;
this.output = new ArrayList<String>();
}
public void run() {
try {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
synchronized (mutex) {
output.add(line);
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
public String[] getLines(boolean clear) {
String[] lines = null;
synchronized (mutex) {
lines = output.toArray(new String[] {});
if (clear)
output.clear();
}
return lines;
}
}
Maybe all this works for you. Let me now if it works...