To provide context, I am taking a reasonably long CSV file with one column of values providing the mean daily temperature from 1960-2016 and am reading them with a BufferedReader like so:
BufferedReader br = new BufferedReader(new FileReader(new File("src/dailyTemp.csv")));
I also have a Swing Application that provides a Boolean value, slowSpeed, to declare whether or not the ScheduledExecutorService should be ran. i.e. Whether or not it should be slow/fast.
The current purpose of this application is to simply adjust whether the next value read is returned instantly or if it is instead scheduled.
public static void main(String[] args) throws IOException
{
startGraph(); //This is the GUI that provides the state of the slowSpeed variable
final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(Main::readFileSlow, 0, 500, TimeUnit.MILLISECONDS);
BufferedReader br = new BufferedReader(new FileReader(new File("src/dailyTemp.csv")));
String newValue = "";
while (newValue != null)
{
if (slowSpeed)
{
newValue = readFileSlow(newValue, br);
} else
{
newValue = readFileFast(newValue, br);
}
totalCount++;
}
br.close();
System.out.println("FIN");
}
public static String readFileSlow(String newValue, BufferedReader br) throws IOException
{
while ((newValue = br.readLine()) != null)
{
System.out.println(newValue);
return newValue;
}
return null;
}
public static String readFileFast(String newValue, BufferedReader br) throws IOException
{
while ((newValue = br.readLine()) != null)
{
System.out.println(newValue);
return newValue;
}
return null;
}
A necessary consideration is that the Reader cannot restart, and therefore the while loop exists to check that.
The main issue I am having, is that the readFileSlow() function cannot take a variable as therefore it is not a Runnable and cannot be controlled by the ScheduledExecutorService.
EDIT 1
Here is my primitive version that reasonably shows how it works to switch:
public class Main
{
static Boolean slowSpeed = true;
public static void main(String[] args) throws IOException, InterruptedException
{
startGraph();
BufferedReader br = new BufferedReader(new FileReader(new File("src/dailyTemp.csv")));
String newValue;
while ((newValue = br.readLine()) != null)
{
if (slowSpeed)
{
System.out.println(newValue);
doSomething(newValue);
TimeUnit.MILLISECONDS.sleep(500);
} else
{
System.out.println(newValue);
doSomething(newValue);
}
totalCount++;
}
br.close();
System.out.println("FIN");
}
public static void toggleSpeed(Boolean newSpeed)
{
slowSpeed = newSpeed;
System.out.println(slowSpeed);
}
}
As far as I can tell, the readFileSlow and readFileFast are identical. Let's pretend it's not. The point is to have two methods that could do different things.
Then, let's fix the readFileSlow and readFileFast a little bit. I'm only showing the readFileSlow, the other looks the same:
public static void readFileSlow(BufferedReader br) throws IOException
{
String newValue = null;
while ((newValue = br.readLine()) != null)
{
System.out.println(newValue);
return;
}
}
What happened?
There is no return type. If we want to call it from a ScheduledExecutorService, then the returned value would be thrown away anyway. The schedule* methods don't return Future -s to retrieve the results. In case of unscheduled reading, i.e. executorService.submit(), we could do something with the return value. But not now.
There is no String newValue variable. Since that variable is copied at function call (passed-by-value), we can define a local variable with the same name. The result will be the same, but the intent will be easier to understand.
Bear with me, we're almost there.
You can wrap these function calls into lambdas like this:
final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
final BufferedReader br = new BufferedReader(new FileReader(new File("src/dailyTemp.csv")));
executorService.scheduleAtFixedRate(() -> {
try {
readFileSlow(br);
} catch (IOException e) {
throw new RuntimeException(e);
}
}, 0, 500, TimeUnit.MILLISECONDS);
We need the try-catch because Runnable is not supposed to throw checked Exception-s. RuntimeException-s and Error-s are okay though.
You can do the same with custom classes that implement Runnable:
private static abstract class FileReaderTask implements Runnable {
protected BufferedReader br;
public FileReaderTask(BufferedReader br) {
this.br = br;
}
protected void doSomethingWithActualLine(String line) {
System.out.println(line);
}
}
private static class SlowFileReaderTask extends FileReaderTask {
public SlowFileReaderTask(BufferedReader br) {
super(br);
}
#Override
public void run() {
try {
String newValue = null;
while ((newValue = br.readLine()) != null)
{
doSomethingWithActualLine(newValue);
return;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
And then you can schedule them like this:
final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
final BufferedReader br = new BufferedReader(new FileReader(new File("src/dailyTemp.csv")));
executorService.scheduleAtFixedRate(new SlowFileReaderTask(br), 0, 500, TimeUnit.MILLISECONDS);
There are couple of other options, like replace the doSomethingWithActualLine() method in FileReaderTask with a lambda that you give to the constructor. You can choose anything - depending on what you want here to do.
Related
I have implemented a way to timeout my process running iperf server side based on this question's top answear and it works as intended but I am not sure how to destroy a process object that I pass inside Task's class constructor.
This is my modified code:
public class Main {
public static void main(String[] args) throws IOException {
Process p=null;
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new Task(p));
try {
System.out.println("Started..");
System.out.println(future.get(5, TimeUnit.SECONDS));
System.out.println("Finished!");
} catch (TimeoutException | InterruptedException | ExecutionException e) {
future.cancel(true);
//gives NullPointerException as expected after thread times out
p.destroyForcibly();
System.out.println("Terminated!");
}
executor.shutdownNow();
}
}
class Task implements Callable<String> {
Process p;
public Task(Process p) {
this.p = p;
}
#Override
public String call() throws Exception {
String s;
String toDisplay = "";
this.p = Runtime.getRuntime().exec("iperf3.exe -s -1");
BufferedReader br = new BufferedReader(new InputStreamReader(this.p.getInputStream()));
while ((s = br.readLine()) != null) {
toDisplay += s + "\n";
}
p.destroyForcibly();
return toDisplay;
}
}
I am guessing I should somehow set main's Process but I have no idea how to aproach this problem
The problem I am doing requires me to send requests to a website and check whether a specific password is correct. It is somewhat similar to a CTF problem, but I use brute force to generate the correct password key, as the site gives feedback whether a specific key is on the right track. In order for a key to be considered "almost-valid," it must be a substring of the correct key.
I have implemented this naively, but the intended solution uses simple parallelism to speed up the process. How would I accomplish this in Java?
import java.net.*;
import java.io.*;
import java.nio.charset.StandardCharsets;
public class Main {
static boolean check(StringBuilder s) throws IOException{
String test = "https://example.com?pass=";
String q = URLEncoder.encode(s.toString(), StandardCharsets.UTF_8);
URL site = new URL(test+q);
URLConnection yc = site.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
//System.out.println(inputLine);
if (inputLine.contains("Incorrect password!")) {
return false;
}
if (inputLine.contains("the correct password!")) {
System.out.println(s);
System.exit(0);
}
}
return true;
}
static void gen(StringBuilder s) throws IOException {
if (!check(s)) {
return;
}
for (int i = 33; i<127; i++) {
int len = s.length();
gen(s.append((char) i));
s.setLength(len);
}
}
public static void main(String[] args) throws IOException, InterruptedException {
gen(new StringBuilder("start"));
}
}
EDIT: I have attempted to implement RecursiveAction & ForkJoinPool, but the code seems just as slow as the naive implementation. Am I implementing the parallelism incorrectly?
import java.nio.charset.StandardCharsets;
import java.util.concurrent.*;
import java.util.*;
import java.io.*;
import java.net.*;
public class cracked4 {
static class Validator extends RecursiveAction{
public String password;
public Validator(String p) {
password = p;
}
#Override
protected void compute(){
try {
if (!valid(password)) return;
System.out.println(password);
ArrayList<Validator> futures = new ArrayList<>();
for (int i = 33; i<127; i++) {
futures.add(new Validator(password + (char) i));
}
for (Validator t: futures) {
ForkJoinTask.invokeAll(t);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public boolean valid(String s) throws IOException {
String test = "https://example.com?pass=" + URLEncoder.encode(s, StandardCharsets.UTF_8);
URL site = new URL(test);
URLConnection yc = site.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
if (inputLine.contains("Incorrect password!")) {
return false;
}
if (inputLine.contains("the correct password!")) {
System.out.println(s);
System.exit(0);
}
}
return true;
}
}
public static void main(String[] args) {
ForkJoinPool forkJoinPool = new ForkJoinPool();
forkJoinPool.invoke(new Validator("cararra"));
}
}
Furthermore, is there a certain UID serial I need? I researched about it, but I could not find a specific answer.
Alright, I researched more about parallelism, and I decided on using ForkJoin / RecursiveAction. Using the parallelism allowed me to reduce my code execution time from 200 seconds to roughly 43 seconds (on my computer).
import java.util.*;
import java.util.concurrent.*;
import java.net.http.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.io.*;
public class cracked4 {
static class Validator extends RecursiveAction {
public StringBuilder password;
public Validator(StringBuilder p) {
password = p;
}
public static boolean valid(StringBuilder s) throws IOException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
String test = "https://example.com?pass=" + URLEncoder.encode(s.toString(), StandardCharsets.UTF_8);
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(test)).GET().build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
String text = response.body();
if (text.contains("Incorrect password!")) {
return false;
}
if (text.contains("the correct password!")) {
System.out.println(s);
System.exit(0);
}
return true;
}
#Override
protected void compute() {
try {
if (!valid(password)) return;
ArrayList<Validator> c = new ArrayList<>();
for (int i = 33; i < 127; i++) {
StringBuilder t = new StringBuilder(password).append((char) i);
c.add(new Validator(t));
}
ForkJoinTask.invokeAll(c);
}
catch (IOException | InterruptedException ignored) {
}
}
}
public static void main(String[] args) {
ForkJoinPool forkJoinPool = new ForkJoinPool();
forkJoinPool.invoke(new Validator(new StringBuilder("start")));
}
}
When I wrote this code initially, I used .fork(), but this did not help at all. In fact, it made it perform just as slow as the sequential code. I collected all of the Validator objects and I used ForkJoinTask.invokeAll(). This small difference resulted in an almost 200% speedup.
Hi please use RecursiveTask,ForkJoinPool for parallelism. Below code is not final modify on your own way.
public class Test {
public static void main(String[] args) {
ForkJoinPool forkJoinPool=new ForkJoinPool(parallelism);
forkJoinPool.invoke(new PasswordKeyValidatorTask(new StringBuilder("start")));
}
public static class PasswordKeyValidatorTask extends RecursiveTask<StringBuilder> {
private static final long serialVersionUID = 3113310524830439302L;
private StringBuilder password;
public PasswordKeyValidatorTask(StringBuilder password) {
this.password = password;
}
#Override
protected StringBuilder compute() {
try {
if (!valid(password)) {
List<PasswordKeyValidatorTask> subtasks = new ArrayList<PasswordKeyValidatorTask>();
for (int i = 33; i < 127; i++) {
PasswordKeyValidatorTask task = new PasswordKeyValidatorTask(password.append((char) i));
subtasks.add(task);
}
subtasks.stream().forEach(t -> t.fork());
return subtasks.stream().map(t -> t.join()).findFirst().orElse(null);
}
} catch (Exception e) {
}
return password;
}
boolean valid(StringBuilder s) throws IOException {
String test = "https://samplewebsite.com?pass=";
String q = URLEncoder.encode(s.toString(), StandardCharsets.UTF_8);
URL site = new URL(test + s);
URLConnection yc = site.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
// System.out.println(inputLine);
if (inputLine.contains("Incorrect password!")) {
return false;
}
if (inputLine.contains("the correct password!")) {
System.out.println(s);
}
}
return true;
}
}
}
I wrote simple method for reading one file and writing into 2 files. Also I wrote this method with 3 threads, where the first thread reads line-by-line file, the second and the third write readed line into own file. My parallel version of method works in 30 times longer than simple sequential method. Please, help to understand what I do wrong, and how I should do this method to not shooting in my leg)))
private static class Tee {
private BufferedReader reader;
private PrintWriter fWriter;
private PrintWriter sWriter;
volatile boolean done;
String buffer;
volatile int readCount;
volatile int firstWriteCount;
volatile int secondWriteCount;
public Tee(BufferedReader reader, PrintWriter fWriter, PrintWriter sWriter) {
this.reader = reader;
this.fWriter = fWriter;
this.sWriter = sWriter;
}
public void teeWhileInsideCo() throws InterruptedException {
Thread reader = new Thread(new LineReader());
Thread fWriter = new Thread(new LineWriter(this.fWriter, 0));
Thread sWriter = new Thread(new LineWriter(this.sWriter, 1));
reader.start();
fWriter.start();
sWriter.start();
reader.join();
fWriter.join();
sWriter.join();
}
private class LineReader implements Runnable {
#Override
public void run() {
String line;
while (true) {
try {
line = reader.readLine();
} catch (IOException e) {
line = null;
}
while (readCount != firstWriteCount || readCount != secondWriteCount) {
}
if (line == null) {
done = true;
break;
}
buffer = line;
readCount++;
}
}
}
private class LineWriter implements Runnable {
private PrintWriter writer;
private int number;
public LineWriter(PrintWriter writer, int n) {
System.out.println(Tee.this);
this.writer = writer;
this.number = n;
}
#Override
public void run() {
while (true) {
while (!done && ((number == 0 ? firstWriteCount : secondWriteCount) == readCount)) {
}
if (done) {
break;
}
writer.println(buffer);
if (number == 0) {
firstWriteCount++;
} else {
secondWriteCount++;
}
}
writer.flush();
}
}
}
Once user entered data timer stops and BuferredReader closed.
If 10 seconds passed and no input - BuferredReader closed and user unable to make input. Below code works, but not 100% correct.
Please suggest any solution.
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
NewThread nt = new NewThread(br);
Thread newThread = new Thread(nt);
newThread.start();
System.out.print("Please enter data: ");
System.out.println("");
String value = br.readLine();
System.out.println(value);
nt.shutdown();
}
}
class NewThread implements Runnable {
volatile BufferedReader br;
volatile boolean running ;
public NewThread(BufferedReader br) throws IOException {
this.br = br;
this.running = br.ready();
}
#Override
public void run() {
int count = 10;
try {
while (!running) {
System.out.print("("+count +")"+ '\r');
Thread.sleep(1000);
count--;
if (count <0){
shutdown();
}
}
} catch (InterruptedException | IOException e) {
e.printStackTrace();
}
}
public void shutdown () throws IOException {
running=true;
br.close();
}
}
So, firsty you calling method:
br.readLine()
BufferedReader implementation of this method uses synchornized block when waiting for user input. Below I put part of code this method:
String readLine(boolean ignoreLF) throws IOException {
StringBuffer s = null;
int startChar;
synchronized (lock) {
ensureOpen();
...}
Nextly, when you call method shutdown from NewThread(after time out) on your reader, which call close method on buffer - execution of this metod uses synchronized mechanism too:
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
try {
in.close();
} finally {
in = null;
cb = null;
}
}
}
so it means that close method will be executed after finished readLine method (exactly after execution synchronized block in readLine method), which is finished when you pass parameter to console.
I suppose that is not possible to close this reader after calling readLine method by standard java mechanism when you use System.in.
Can someone please explain to me what I am doing wrong with the below code?
I am using the executeJavascript method to send a series of commands to the Webview, I want to loop through each command and then wait an arbitrary amount of time before the next command is executed.
What actually happens when I run this is that the application will hang every-time I pause in the loop, then once the loop is complete all my javascript actions happen at once. I thought by wrapping my executeJavascript into the Runlater class that it would all be synced nicely with the Application thread...
I seem to be going round in circles so help/direction would be appreciated, thanks.
I have set up three classes, A: Main.class that contains the following:
...scene.setOnKeyPressed(event -> {
switch (event.getCode()) {
case SPACE:
scriptRunner.run();
case SHIFT:
B: ScriptRunner.class that contains the following:
public class ScriptRunner extends Task<Void> {
#Override
protected Void call() throws Exception {
printOut("Running Test");
try (InputStream fileInputStream = new FileInputStream("test.txt");
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, Charset.forName("UTF-8"));
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);) {
String getCurrentLine;
StepRunner stepRunner = new StepRunner();
while ((getCurrentLine = bufferedReader.readLine()) != null) {
final String currentLine = getCurrentLine;
Platform.runLater(new Runnable() {
#Override
public void run() {
stepRunner.runStep(currentLine);
}
});
Thread.sleep(3000);
}
printOut("Test finished");
bufferedReader.close();
} catch (
IOException e) {
e.printStackTrace();
}
return null;
}
C: StepRunner.class that contains the following:
public class StepRunner extends Task<Void> {
private String currentCommand;
public StepRunner (String currentCommand){
this.currentCommand = currentCommand;
}
#Override
protected Void call() throws Exception {
printOut("Got Here with " + currentCommand);
WebEngine.executeJavascript(currentCommand);
return null;
}
}
Try to extend your ScriptRunner class in Thread
public class ScriptRunner extends Thread {
#Override
public void run() {
printOut("Running Test");
try (InputStream fileInputStream = new FileInputStream("test.txt");
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, Charset.forName("UTF-8"));
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);) {
String getCurrentLine;
StepRunner stepRunner = new StepRunner();
while ((getCurrentLine = bufferedReader.readLine()) != null) {
final String currentLine = getCurrentLine;
Platform.runLater(new Runnable() {
#Override
public void run() {
stepRunner.runStep(currentLine);
}
});
Thread.sleep(3000);
}
printOut("Test finished");
bufferedReader.close();
} catch (
IOException e) {
e.printStackTrace();
}
}
}
then to call
Thread scriptRunner = new Thread(new ScriptRunner());
scriptRunner.run();
I think the problem is Thread.sleep(3000); that cause the app to hang. The process should be run on Thread.