I have a directory with JSON files which needs to be iterated to get the name of document dName. Multiple JSON files can have same dName. Then a symbolic link needs to be created to that JSON file from a folder named output/dName/match. The threads first check if the dName folder exists first if not it creates them first. I have the following code that creates symbolic links.
protected static void copyFile(String docName, Path tFilePath) throws IOException {
final String docFolderName = "output" + docName.substring(0, docName.lastIndexOf("."));
final String opDir = docFolderName + "match";
path = Paths.get(opDir);
if (Files.notExists(path)) {
Files.createDirectories(path);
outputAnnotationDirs.add(path.toString());
}
try {
Files.createSymbolicLink(Paths.get(opDir).resolve(tFilePath.getFileName()), tFilePath);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
protected static void Mapper(String Dir,int numThreads) throws Exception {
final ExecutorService executorService = Executors.newFixedThreadPool(numThreads);
final ConcurrentLinkedQueue<Future<?>> futures = new ConcurrentLinkedQueue<Future<?>>();
final JsonParser parser = new JsonParser();
try {
Files.walkFileTree(Paths.get(Dir), new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult visitFile(final Path tFile, BasicFileAttributes attrs) throws IOException {
futures.add((Future<String>) executorService.submit(new Runnable() {
public void run() {
JsonObject jsonObject = null;
FileReader reader = null;
try {
reader = new FileReader(tFile.toFile());
jsonObject = (JsonObject) parser.parse(reader);
JsonArray instancesArray = (JsonArray) jsonObject.get("instances");
String dName = instancesArray.get(0).getAsJsonObject().get("dname").toString();
copyFile(dName, tFile);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (reader != null)
reader.close();
} catch (IOException e) {
logger.error(e);
}
}
}
}));
return FileVisitResult.CONTINUE;
}
});
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
Future<?> future;
while ((future = futures.poll()) != null) {
try {
future.get();
} catch (Exception e) {
for (Future<?> f : futures)
f.cancel(true);
if (executorService != null)
executorService.shutdown();
throw new Exception(e);
}
}
if (executorService != null)
executorService.shutdown();
}
}
However an exception keeps occurring at the line where symbolic link is created.
Exception in thread "main" java.lang.Exception: java.util.concurrent.ExecutionException: java.lang.RuntimeException: java.nio.file.NoSuchFileException:`
Ex: Exception at output/document1/match/ok.json
If I'm right the symbolic links are created only after that line gets executed. Then why does the error occur? And individual symbolic Link creation by a thread why does it cause concurrent.ExecutionException?
Then why does the error occur?
The error occurs because your "parent directory creation" is not creating all parent directories before creating the symlink. For eg: If you have json entry of "dname": "a/b/c/somedname1.txt" - folders a/b/c don't seem to be created. That's why NoSuchFileException is thrown. Now, you already do have a logic to create directories, but why did that not work? That would have worked fine, had you run it in a single thread. Why not in multiple threads?
Because, the path variable is shared across all threads and is simultaneously getting modified by many threads.
path = Paths.get(opDir);
if (Files.notExists(path)) {
Files.createDirectories(path);
outputAnnotationDirs.add(path.toString());
}
When run in multiple threads, say, one thread has dname:a/b/c/dname1.txt and a second thread has dname:e/f/g/dname2.txt. The first thread may end up creating e/f/g instead of a/b/c directories. The classic concurrency problem. Making that path a local variable will solve your issue immediately. Or run your process in a single thread.
Had your original file gotten removed by another process, you would have gotten a java.io.FileNotFoundException.
Had your symlinks were already present, you would have gotten a java.nio.file.FileAlreadyExistsException.
java.nio.file.NoSuchFileException happens when you cannot act on the file, like DELETE. Or when you try to create a file/symlink when parent folders aren't there.
And individual Symbolic Link creation by a thread why does it cause
concurrent.ExecutionException?
The NoSuchFileException is wrapped by your RunTimeException is wrapped by ExecutionException when you do a get on the future. Because, the RunTimeException happened on a different thread and your below call happens on the main thread. So Executor wraps the Exception and fires at the below call which is invoked from the main thread.
future.get();
Thank you.
As stated in my comment:
path = Paths.get(opDir);
is a race condition.
Simple.. There is a race condition. Change the scope of the relative path variable to a local variable.
To me it looks like NoSuchFileException tells you what is the problem. To create symbolic link to a file, the file should exist.
Related
I wrote a method to close write to a file.
However, a senior developer suggested me to close the file inside the finally block.
This is the method I have:
private static void writetoFiles(String error) {
try {
File file = new File("errorcode.txt");
if (!file.exists()) {
file.createNewFile();
} else {
FileWriter updateerrorcode = new FileWriter("errorcode.txt");
updateerrorcode.write(error);
updateerrorcode.close();
}
} catch (IOException e) {
}
}
I read many answers in stackoverflow but all of them seemed a bit too complicated for a simple case like mine.
Any suggestions how should I go about this?
The cleanest approach would be to do it using the try-with-resources statement as shown below:
private static void writetoFiles(String error) throws IOException {
//...
try (FileWriter updateerrorcode = new FileWriter("errorcode.txt")) {
updateerrorcode.write(error);
}
//...
}
Do not catch an exception in a method if it can not handle it:
If the method, writetoFiles can not handle the exception, it should throw the same so that the calling method can handle it appropriately.
Use a try-with-resource statement:
private static void writetoFiles(String error) {
try {
File file = new File("errorcode.txt");
if (!file.exists()) {
file.createNewFile();
} else {
try (FileWriter updateerrorcode = new FileWriter("errorcode.txt")) {
updateerrorcode.write(error);
}
}
} catch (IOException e) {
// TODO: Handle error condition
}
}
To point out a separate issue...I think your logic is wrong in your example. If the output file doesn't exist, all your code does is create the file. Only if the file already exists does it write the error text to it. I expect that you want to write the text in either case. If this is true, you don't need the createNewFile call at all, as the FileWriter class will create the file if it doesn't already exist. So I think what you really want is this:
private static void writetoFiles(String error) {
try (FileWriter updateerrorcode = new FileWriter("errorcode.txt")) {
updateerrorcode.write(error);
} catch (IOException e) {
// TODO: Handle error condition
}
}
This will cause the writer to be properly closed in both the normal execution case and the error throw case. I assume that in your actual code, you'll do something with that IOException when it is caught. I can't know what you want to do there, so I won't propose anything.
If you want to strictly use a finally block, you can do this instead:
FileWriter updateerrorcode = new FileWriter("errorcode.txt");
try {
updateerrorcode.write(error);
}
catch (IOException e) {
// TODO: Handle error condition
}
finally {
updateerrorcode.close();
}
This is the only option you would have had in earlier versions of Java, prior to the addition of the try-with-resource construct. In this second method, you might want to catch an error from close(), but in all of my 25+ years of experience with Java, I don't recall a close() call on a file failing. I guess you'd get that if you were out of disk space on your target volume and so close() couldn't flush the stream's write buffer. This issue is a distinct advantage of the newer method...failure to close the file won't affect the throw/catch of an exception thrown by the write() call.
This question already has an answer here:
How to show a progress bar while downloading in javafx
(1 answer)
Closed 7 years ago.
Hello Guys I have a question that how to run the task in background in Javafx
Currently the situation is that I have created a Copy Function in javafx, it is working absolutely fine, but if we have more files, then it goes in not responding mode till the process completes, Logs are also not printed in my textarea, Every file is being copied in the respected folder, but the problem is its hanged till the process completes,
And One more question how to run this program forever means whenever a new file comes in source directory it automatically goes to the destination directory.
Here is my code
try
{
sourceFile = new File(sourcePath).listFiles();
syslog.appendText("\nTotal Files in the Directory : " + sourceFile.length);
for(int i = 0; i<sourceFile.length;i++)
{
if(sourceFile[i].isFile())
{
String file = sourceFile[i].getName();
String extension = Files.getFileExtension(file);
if(!new File(destinationPath+"/"+extension.toUpperCase()).exists())
{
if(new File(destinationPath+"/"+extension.toUpperCase()).mkdir())
{
syslog.appendText("\nDirectory Created : " + destinationPath+"/"+extension.toUpperCase());
try
{
if(!new File(destinationPath+"/"+extension.toUpperCase()+"/"+file).exists())
{
syslog.appendText("\nFile "+file+" is processing to copy to "+destinationPath+"/"+extension.toUpperCase());
copyFile(sourceFile[i],new File(destinationPath+"/"+extension.toUpperCase()+"/"+file));
syslog.appendText("\nFile "+file+" is successfully copied to "+destinationPath+"/"+extension.toUpperCase());
if(sourceFile[i].delete())
syslog.appendText("\nFile "+file+" is successfully deleted from "+sourcePath);
else
syslog.appendText("\nError in deleting File "+file+" from "+sourcePath);
}
}
catch(Exception e)
{
e.printStackTrace();
syslog.appendText("\nSome Error Occurred while copying the File : "+sourceFile[i]);
}
}
}
else
{
try
{
if(!new File(destinationPath+"/"+extension.toUpperCase()+"/"+file).exists())
{
syslog.appendText("\nFile "+file+" is processing to copy to "+destinationPath+"/"+extension.toUpperCase());
copyFile(sourceFile[i],new File(destinationPath+"/"+extension.toUpperCase()+"/"+file));
syslog.appendText("\nFile "+file+" is successfully copied to "+destinationPath+"/"+extension.toUpperCase());
if(sourceFile[i].delete())
syslog.appendText("\nFile "+file+" is successfully deleted from "+sourcePath);
else
syslog.appendText("\nError in deleting File "+file+" from "+sourcePath);
}
}
catch(Exception e)
{
e.printStackTrace();
syslog.appendText("\nSome Error Occurred while copying the File : "+sourceFile[i]);
}
}
}
}
syslog.appendText("\nFinished..........");
}
catch (Exception e)
{
e.printStackTrace();
}
And this is the copy Function
private static void copyFile(File source, File destination)
throws IOException {
FileChannel inputChannel = null;
FileChannel outputChannel = null;
try {
inputChannel = new FileInputStream(source).getChannel();
outputChannel = new FileOutputStream(destination).getChannel();
outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
} finally {
inputChannel.close();
outputChannel.close();
}
}
You need to create a Task and add it to a new thread. It looks like this:
Task<T> backgroundTask = new Task<T>() {
#Override
protected T call() throws Exception {
return null;
}
#Override
public void run() {
try {
copyFile(source,destination); //or any other operation you want to have in a thread.
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
Thread backgroundThread = new Thread(backgroundTask);
backgroundThread.setDaemon(true); //true if you want to have it running excuslivly when having your parent-threat running
You can call and run this thread once with
backgroundThread.run();
Futher you can check the state of the thread with
backgroundThread.state();
which could be helpful if you want to check e.g. if your thread is still in process.
Consider collisions with your javafx-thread. If you want to alter a object which is accessed by the javafx-thread you need to perform a
Platform.runLater(new Runnable() {/*your impact on javafx*/});
I Would sugest to use a Task, something like this:
public class CopyFileTask<Void> extends Task<Void> {
#Override
protected void succeeded() {
super.succeeded();
// e.g. show "copy finished" dialog
}
#Override
protected void running() {
super.running();
// e.g. change mouse courser
}
#Override
protected void failed() {
super.failed();
// do stuff if call threw an excpetion
}
#Override
protected Void call() {
// do expensive the expensive stuff
copyStuff(source, destination)
return null ;
}
}
The convenience methods succeeded, running and failed are executed in the JavaFX GUI thread, while the stuff in call is executed in another thread. To run the Task, I would suggest to submit it to an ExecuterService
ExecutorService exService = Executors.newSingleThreadExecutor();
exService.submit(new CopyFileTask());
I have a bunch of parser classes that subclass a PriseParser class and implement a getAllPrices() method (called by the PriseParser.getPrices() that does some other stuff too not related to this post) in order to acquire some data from various web sites. Below is an example for such an implementation:
#Override
public List<Price> getAllPrices() throws ParserException,
InterruptedException {
LogFactory.getFactory().setAttribute("org.apache.commons.logging.Log",
"org.apache.commons.logging.impl.NoOpLog");
java.util.logging.Logger.getLogger("com.gargoylesoftware.htmlunit")
.setLevel(Level.OFF);
java.util.logging.Logger.getLogger("org.apache.commons.httpclient")
.setLevel(Level.OFF);
List<Price> prices = new ArrayList<price>();
WebClient webClient = new WebClient(BrowserVersion.FIREFOX_24);
HtmlPage page;
try {
page = webClient.getPage(URL);
if(Thread.currentThread().isInterrupted()){
System.out.println("INTERRUPTED BEFORE CLOSE");
}
//my parsing code here that fills prices list. Includes calls to webClient.waitForBackgroundJavaScript in some places
webClient.closeAllWindows();
if(Thread.currentThread().isInterrupted()){
System.out.println("INTERRUPTED AFTER CLOSE");
}
} catch (InterruptedException e) {
throw e;
} catch (Exception e) {
throw new ParserException(e);
}
return prices;
}
These parsers are run concurrently with an ExecutorService:
public List<Price> getPrices(List<PriceParser> priceParsers) throws InterruptedException {
ExecutorService executorService = Executors
.newFixedThreadPool(PriceParsers.size());
Set<Callable<List<Price>>> callables = new HashSet<Callable<List<Price>>>();
List<Price> allPrices = new ArrayList<Price>();
for (PriceParser PriceParser : PriceParsers) {
callables.add(new Callable<List<Price>>() {
public List<Price> call() throws Exception {
List<Price> prices = new ArrayList<Price>();
prices = PriceParser.getPrices();
return prices;
}
});
}
List<Future<List<Price>>> futures;
try {
futures = executorService.invokeAll(callables);
for (Future<List<Price>> future : futures) {
allPrices.addAll(future.get());
}
} catch (InterruptedException e) {
throw e;
} catch (ExecutionException e) {
logger.error("MULTI-THREADING EXECUTION ERROR ", e);
throw new RuntimeException("MULTI-THREADING EXECUTION ERROR ", e);
} finally {
executorService.shutdownNow();
}
return allPrices;
}
The two if(Thread.currentThread().isInterrupted()){} pieces of code in the first method, were added in order to check the following issue I have observed: When the executor service is interrupted (this can happen from a gui application that terminates the thread when pressing a cancel button), the first interruption check I inserted in my code successfully prints "INTERRUPTED BEFORE CLOSE".
However the second check does not print anything. It seems therefore that somehow one of the calls to webClient I make (which are waitForBackgroundJavaScript method calls and the webClient.closeAllWindows() call at the end) clears the thread interruption status. Can someone explain why is this actually happening?
It seems that the problem lies in a call to webClient.waitForBackgroundJavaScript performed by my parsing code. Internally this goes as far as waitForJobs method of HtmlUnit's JavaScriptJobManagerImpl method. And this method contains the following piece of code that essentially swallows all InterruptedExceptions and therefore the ability for any caller to be able to identify if any interruptions were made during that call:
try {
synchronized (this) {
wait(end - now);
}
// maybe a change triggers the wakup; we have to recalculate the
// wait time
now = System.currentTimeMillis();
}
catch (final InterruptedException e) {
LOG.error("InterruptedException while in waitForJobs", e);
}
Instead of catching and just logging, it should just let the exception be thrown
I have a Java application that watches a directory and when XML files are added to that directory, it parses out data from the XML file.
It works file as a single-threaded application, but I'm thinking out making it multi-threaded so multiple files can be processed simultaneously.
Question is, when thread #1 finds a file and starts processing it, how can I mark the file as 'in progress' so thread #2 doesn't try to process it to?
I was thinking that the thread could simply rename the file once it starts working on it, to myfile.xml.inprogress, and then myfile.xml.finished when done.
But if I do that, is it possible that two threads will see the file at the same time and both will try to rename it simultaneously?
I might also want to run two instances of this application reading files in the same directory, so whatever path I take supports multiple processes.
Thanks!
You should use a Producer-Consumer pattern. Have one thread to listen for changes in the files and pass off that work to other threads.
You can use a BlockingQueue for this to make the code very simple.
First you need two classes, a producer:
class Producer implements Callable<Void> {
private final BlockingQueue<Path> changedFiles;
Producer(BlockingQueue<Path> changedFiles) {
this.changedFiles = changedFiles;
}
#Override
public Void call() throws Exception {
while (true) {
if (something) {
changedFiles.add(changedFile);
}
//to make the thread "interruptable"
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(1));
} catch (InterruptedException ex) {
break;
}
}
return null;
}
}
And a Consumer:
class Consumer implements Callable<Void> {
private final BlockingQueue<Path> changedFiles;
Consumer(BlockingQueue<Path> changedFiles) {
this.changedFiles = changedFiles;
}
#Override
public Void call() throws Exception {
while (true) {
try {
final Path changedFile = changedFiles.take();
//process your file
//to make the thread "interruptable"
} catch (InterruptedException ex) {
break;
}
}
return null;
}
}
So, now create an ExecutorService, submit one Producer and as many consumers as you need:
final BlockingQueue<Path> queue = new LinkedBlockingDeque<>();
final ExecutorService executorService = Executors.newCachedThreadPool();
final Collection<Future<?>> consumerHandles = new LinkedList<>();
for (int i = 0; i < numConsumers; ++i) {
consumerHandles.add(executorService.submit(new Consumer(queue)));
}
final Future<?> producerHandle = executorService.submit(new Producer(queue));
So you guarantee that only one file is being worked on at a time because you control that yourself. You also do so with minimum synchronisation.
It might be worthwhile the Consumer also reading the file to remove the the shared disc IO that will happen otherwise - this will likely slow the system down. You could also add another Consumer that writes changed files at the other end to completely eliminate shared IO.
To shutdown the system simply call:
executorService.shutdownNow();
executorService.awaitTermination(1, TimeUnit.DAYS);
Because your workers are interruptible this will bring down the ExectuorService once tasks currently in progress have finished.
Producer Consumer is definitely the idea here.
With Java 7 there is a WatchService provided which can take care of the Producer problem even though it is a pain to work with.
Have an ExecutorService with the desired pool size to take care of Consumers.
Here is it how it all wires up.
public class FolderWatchService {
private ExecutorService executorService = Executors.newFixedThreadPool(5);
public void watch() throws Exception {
Path folder = Paths.get("/home/user/temp");
try (WatchService watchService = FileSystems.getDefault().newWatchService()) {
folder.register(watchService,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.ENTRY_DELETE);
while(true) {
final WatchKey key = watchService.take();
if (key != null) {
for (WatchEvent<?> watchEvent : key.pollEvents()) {
WatchEvent<Path> event = (WatchEvent<Path>) watchEvent;
Path dir = (Path) key.watchable();
Path absolutePath = dir.resolve(event.context());
executorService.submit(new WatchTask(absolutePath));
}
key.reset();
}
}
}
}
public static void main(String[] args) throws Exception {
FolderWatchService folderWatchService = new FolderWatchService();
folderWatchService.watch();
}
}
class WatchTask implements Runnable {
private Path absolutePath;
WatchTask(Path absolutePath) {
this.absolutePath = absolutePath;
}
#Override
public void run() {
System.out.println(Thread.currentThread().getName() + absolutePath.toAbsolutePath());
try (BufferedReader reader = Files.newBufferedReader(absolutePath , StandardCharsets.UTF_8)) {
//Do read
reader.lines().forEach(line -> System.out.println(line));
} catch (IOException e) {
e.printStackTrace();
}
}
}
You can use java.nio.channels.FileLock: http://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileLock.html to synchronize access between different processes.
For synchronization between different threads running inside the same process, you can use java.util.concurrent.locks.Lock: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Lock.html
This question already has answers here:
How to start/stop/restart a thread in Java?
(9 answers)
Closed 7 years ago.
I have created a program which searches for files in a source folder. If it finds any file, it processes that file and moves it to a destination folder, then looks for a new file in the source folder. It has to keep on checking the source folder for a file.
I have used a thread to look for files in the source folder. The problem I am facing is whenever any exception is thrown during file processing, the thread gets stopped. I want the thread to be running even if an exception is thrown. It has to move the file that caused the error to some other folder and look for a new file in the source folder. How can I make the thread keep on running?
Eg:
public void run() {
try {
searchfile();
}
catch(Exception e) {
e.printStackTrace();
}
}
public void searchfile(){
...
}
Update :
I should be more clear in my question. Actually there are 4 source folders and 4 destination folders. I have to perform the same operation in each source & destination pair. So i have created 4 threads in one class and do the operation in separate class.
class MainClass
{
public static void main(String[] args){
for(int i=0;i<4;i++){
SearchClass search = new SearchClass();
Thread thread = new Thread(search);
thread.start();
}
}
}
class SearchClass
{
public void run() {
try {
searchfile();
} catch(Exception e) {
e.printStackTrace();
}
}
public void searchfile(){ ... } }
All the thread wont stop running eventhough it caught any exception in middle. How can i do that?
If a thread is dying due to an uncaught exception, the answer is simple: catch the exception at an appropriate place so that you can keep going. Either catch the exception within your searchfile method, or make the run method call searchfile in a loop.
If you want your thread to keep running use a loop.
public void run() {
while(!Thread.interrupted())
try {
searchfile();
}
catch(Exception e) {
e.printStackTrace();
}
}
Inside your catch, you can move the file to the error folder then create a new object of the same thread and start it again.
unless i got you wrong, your code is missing the "keep running" nature, i.e. you need to have a loop somewhere:
public static void main(String[] args){
ExecutorService service = Executors.newFixedThreadPool(4);
// for each of your 4 folders
while (true) {
Future<File> searchResult = service.submit(new SearchTask());
try {
File foundFile = searchResult.get();
// handle found file
} catch (Exception e) {
// handle exception
}
}
}
private static class SearchTask implements Callable<File> {
#Override
public File call() {
return searchFile();
}
public File searchFile() {
// search & return found file
}
}
note that this is just a very simple extension of your example. it is still missing the parametrization of the SearchTask to actually be specific for a folder, handling of files & exceptions, etc. as mentioned in previous answers, your SearchTask should implement Runnable (i prefer Callable...), and IMHO it's always better to use an ExecutorService than to spawn threads manually. hope this helps...
I'm not entirely sure if this will work, yet here's a try.
public void run() {
try {
searchFile();
} catch(Exeption e) {
e.printStackTrace();
if(!Thread.currentThread().isAlive())
Thread.currentThread().start();
}
}
you said that the exception may be thrown during file process , so i put the processFile() in a try-catch block. but if it may be thrown during search, you may put it in a try-catch too.
public void run() {
while(!terminated) {
findNextFile();
try {
processFile();
} catch {
// handle error
}
}
}
Here are my assumptions based on your question and your clarification:
Each thread, in the run() method, only calls searchfile() once and not in a loop
your searchfile() method has a loop in it and you want that loop to continue running even if an exception is thrown in it.
you have some way of initializing each thread that you aren't showing us (and that isn't terribly important for this specific quiestion)
searchfile() does not declare that it throws any Exception
You aren't using a logging framework, but are instead using System.out (although using a logging framework is a Really Good Idea
Java 5 is OK (otherwise you'll have to use a different for() loop below
With these assumptions, you don't want to plan to catch an Exception in your run() method except for the purpose of logging that something went very wrong:
public void run() {
try {
searchfile();
} catch (RuntimeException e) {
System.out.println("Something went very wrong! Unexpected RuntimeException");
e.printStackTrace();
}
}
Note that the code catches RuntimeException. Always catch the most specific Exception that will do what you need. Then what you need is something such as the following in your searchfile() method:
File[] files = directory.listFiles();
for (File file : files) {
try {
// Do your normal file/directory processing here
} catch (Exception e) {
System.out.println("Exception processing file " + file.getName() + " " + e);
// Move "file" to another area
}
}
Since you are trapping unexpected Exceptions in the main loop of your Thread, your thread will continue processing after handling the Exception.
You can easily go with a workaround. Just run the needed logic for some amount of times and finish the job based on some criteria.
public class ThreadRestartWorkaround extends Thread {
public static void main(String[] args) {
ThreadRestartWorkaround th = new ThreadRestartWorkaround(5);
th.start();
}
private int maxCycles;
private int currentCycle;
public ThreadRestartWorkaround(int maxCycles) {
this.maxCycles = maxCycles;
}
#Override
public void run() {
while(executeSomeLogicUntilReachingTheLimit());
System.out.println("Finished due to exceeding the maxCycles config");
}
private boolean executeSomeLogicUntilReachingTheLimit() {
currentCycle++;
System.out.println("Executing logic for " + currentCycle + " time");
return currentCycle < maxCycles;
}
}
And the output is
Executing logic for 1 time
Executing logic for 2 time
Executing logic for 3 time
Executing logic for 4 time
Executing logic for 5 time
Finished due to exceeding the maxCycles config