I'd like to have my thread (the main/EDT) wait until changes to a file occur and then wait. DefaultFileMonitor extends Runnable and hence runs in a thread of its own. Here is a SSCE:
import java.io.File;
import org.apache.commons.vfs.*;
import org.apache.commons.vfs.impl.DefaultFileMonitor;
public class FileChangeListener implements FileListener {
DefaultFileMonitor fm;
public final static File logFile = new File("t.txt");
public void startListening() throws FileSystemException {
final FileSystemManager fsManager = VFS.getManager();
final FileObject listendir = fsManager.toFileObject(logFile);
fm = new DefaultFileMonitor(this);
fm.addFile(listendir);
fm.start();
}
#Override
public void fileCreated(FileChangeEvent fce) throws Exception {
fileChanged(fce);
}
#Override
public void fileDeleted(FileChangeEvent fce) throws Exception {
//hmm..why deleted?
}
#Override
public void fileChanged(FileChangeEvent fce) throws Exception {
System.out.println("fileChanged executed");
}
}
The main:
import java.io.PrintWriter;
public class App {
public static void main(String[] args) {
FileChangeListener fcl = new FileChangeListener();
try {
fcl.startListening();
final PrintWriter printWriter = new PrintWriter(FileChangeListener.logFile);
printWriter.println("Hello Threads!");
printWriter.close();
//EXECUTE THE FOLLOWING ONLY AFTER fileChanged
System.out.println("Mission complete.");
} catch (Exception ex) {
}
}
}
Append the following to App.main(..) after printWriter.close():
synchronized (fcl) {
fcl.wait();
}
//EXECUTE THE FOLLOWING ONLY AFTER fileChanged
System.out.println("Mission complete.");
and append the following to FileChangeListener.fileChanged(..) after System.out.println("fileChanged executed"):
synchronized (this) {
this.notifyAll();
}
You could communicate between teh two using "Conditions" : http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Condition.html
Basically, create a new "shared" Condition (say fileChanged). Now, whenever the file changes (in fileChanged() trigger this condition (fileChanged.signal()). In your main code, wait for this condition to occur (fileChanged.await()).
Hope you get the idea.
For making the condition accessible to multiple code unit, here is what I can think (decreasing order of preference) :
Assuming you are going to need as many conditions as many files you listen to, create a factory method getCondition(String file path/name/attribute) which will return the Condition object based on the file (its path or name or other attributes). Use this factory method to get the condition in all cases. The factory should internally create new Condition() instances for each new file to be listened to AND must throw away older instances as the processing of the files is complete (so probably you should add a destroy/deleteCondition(String file) method as well.)
Store the condition as a public field in the listener class (kind of hack if you have the listener instance available).
Store the condition as a public static field in the listener class (kind of hack if you have only one listener instance throughout).
Why? FileChangeListener is a callback: it is executed when the event occurs. In this specific case you've just closed the file so you alreayd know that the mission is complete on that file, so just proceed to the next step. I don't see why you need a FileChangeListener at all here.
Related
This a much simplified version of my multithreading project and its just a way to replicate the issue in a simpler way for easy understanding.
So I have two classes startSession.java and main.java
what I am trying to do is to send a variable from startSession.java to main.java and Im also using multithreading. However, the problem I am facing is that everytime I try to retrieve the variable inside main I get a null value.
Inside startSession theres the run method and Setter(setSessionKey(String sess)) and getter(getSessionKey()) methods. I hardcoded a variable to test.
The get method only works inside the run method but when I call getSessionKey() from inside main I get a null as seen below. However, this is only a problem when I am using multithreading. When I dont use multithreading and instead just call the run method from inside main, the variable Im looking for is no longer null.
My question is there a way to send a variable from startSession to main while using multithreading ?
thank you
startSession.java
public class startSession extends Thread {
static String sessionKey;
public void run() {
String createdSession = "83248329";
setSessionKey(createdSession);
System.out.println("Inside run method: " + getSessionKey());
}
public String getSessionKey() {
return sessionKey;
}
public void setSessionKey(String sess) {
sessionKey = sess;
}
}
main.java
package com.Server;
public class Main {
static String session;
public static void main(String[] args) throws InterruptedException {
startSession startSession = new startSession();
startSession.start();
session = startSession.getSessionKey();
System.out.println("Inside Main: " + session);
}
}
with multithreading
without multithreading
Use a BlockingQueue whereby the Thread (Producer) will add to the shared queue and the Main (Consumer) will block on the take
main
public static void main(String[] args) throws Exception {
// example only uses 1024 - check what is best for you
BlockingQueue queue = new ArrayBlockingQueue(1024);
StartSession producer = new StartSession(queue);
....
System.out.println(queue.take());
startSession
String createdSession= "83248329";
queue.add(createdSession);
see https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/BlockingQueue.html
and
https://jenkov.com/tutorials/java-util-concurrent/blockingqueue.html
I have to map exit code 2 whenever input file is not located in the source folder in spring batch.I have tried by implementing listener but batch terminate before starting and return exit code 1. It doesn't reach to the listener to map it with exit code 2. So can someone help me in that.Thanks in advance.
I'm assuming you mean the EXIT_CODE in the BATCH_STEP_EXECUTION table, not the exit code from like System.exit(int x).
In that case, it's probably easier to just change the reader not to throw the Exception (and instead just return null when the read() method executes. The FlatFileItemReader makes this easy by just setting the strict property to false.
If you meant the actual JVM exit code (which is pretty gross), then you'd basically have to register a StepExecutionListener and then inform the calling class that the failure occurred... please note: I don't recommend this pattern
// In MainClass
private static final AtomicBoolean fileNotFound = new AtomicBoolean(false);
public static void main(String[] args) {
// launch job
if (fileNotFound.get()) {
System.exit(2);
}
}
public static void setFileNotFound(boolean bool) {
fileNotFound.set(bool);
}
// In StepExecutionListener
public void afterStep(StepExecution stepExecution) {
for (Throwable error : stepExecution.getFailureExceptions()) {
if (error instanceof IllegalArgumentException && "source cannot be null".equals(error.getMessage())) {
MainClass.setFileNotFound(true);
}
}
}
I am new to the java multithreading programming. I know that it can be done by thread communication but i don't know how to proceed. I don't know how one thread would notify another if some changes are done in a file. The problem is mentioned below.
I have a comma separated file in which some lines are written. I want two threads to be started from my main thread. The csv file might be appended externally/manually. One of the thread will notify second thread if some changes are done in csv file and second thread will read that file concurrently line by line and perform some task.
Thanks.
You can use java.nio.file.WatchService for this purpose.
Refer Tutorial
From the link:-
The Watch Service API is designed for applications that need to be
notified about file change events. It is well suited for any
application, like an editor or IDE, that potentially has many open
files and needs to ensure that the files are synchronized with the
file system. It is also well suited for an application server that
watches a directory, perhaps waiting for .jsp or .jar files to drop,
in order to deploy them.
You create two thread, that inside their run method, they both use one Object as the thread wait and notify signal.
The first thread (T1), would synchronize on the object and wait on it.
The second thread (T2), would synchronize on the object, do something with it, and signal a notify.
The following snippets should give you idea... (please disregard about the endless loop and bad exception handling, its just to express the idea for ease of understanding).
public class IdeaOfThreadingWithWaitAndNotify {
public static void main(String[] args) {
File f = new File("grow.txt");
if(!f.exists()) {
try {
f.createNewFile();
Thread appenderThread = new Thread(new FileAppender(f));
Thread checkerThread = new Thread(new FileSizeCounter(f));
appenderThread.start();
checkerThread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static class FileAppender implements Runnable {
private File file;
private FileOutputStream fos;
public FileAppender(File file) throws FileNotFoundException {
super();
this.file = file;
fos = new FileOutputStream(file);
}
public void run() {
while(true) {
synchronized (file) {
try {
fos.write("Appended... ".getBytes());
fos.flush();
file.notify();
Thread.sleep(1000);
} catch (IOException e) {
} catch (InterruptedException e) {
}
}
}
}
}
public static class FileSizeCounter implements Runnable {
private File file;
public FileSizeCounter(File file) {
super();
this.file = file;
}
public void run() {
while(true) {
synchronized (file) {
try {
file.wait();
} catch (InterruptedException e) {
}
System.out.println("File changed .. now size is " + file.length());
// you can do other stuff with the file...
}
}
}
}
}
there you can see, between the two thread, they are sharing the same "file" instance and use it as the wait and notify signaling. Object who call the wait will have its execution flow stop right there, until the other thread call a notify on it. Then the waiting thread can continue.
I hope this helps.
I am trying to implement a timeout while listing files in java considering that listing files should be IO bound with some CPU need as well. Following is the code:
FileLister:
package com.timeout;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class FileLister implements Runnable{
private String fileLocation;
private List<String> fileList = new ArrayList<String>();
public FileLister(String fileLocation){
this.fileLocation = fileLocation;
}
public void run(){
this.listFiles(this.fileLocation);
}
public void listFiles(String fileLocation){
File file = new File(fileLocation);
File testFile = null;
String[] fileList = file.list();
if(null!=fileList){
for(String fileName:fileList){
testFile = new File(fileLocation+"/"+fileName);
if(testFile.isDirectory()){
listFiles(fileLocation+"/"+fileName);
}else{
synchronized(this){
this.fileList.add(fileLocation+"/"+fileName);
}
}
}
}
}
public List<String> getFileList() {
return fileList;
}
}
Timer:
package com.timeout;
public class Timer implements Runnable{
private long timeout;
public Timer(long timeout){
this.timeout = timeout;
}
public void run(){
long expectedEndTime = System.currentTimeMillis() + this.timeout;
System.out.println("expectedEndTime---"+expectedEndTime);
while(System.currentTimeMillis()<expectedEndTime){
}
System.out.println("endTime---"+System.currentTimeMillis());
System.exit(0);
}
}
Calling class:
package com.timeout;
import java.io.IOException;
public class Timeout {
public static void main(String[] args)throws IOException{
FileLister fl = new FileLister("C:/");
Timer tm = new Timer(10000);
Thread flt = new Thread(fl);
Thread tmt = new Thread(tm);
flt.start();
try{
Thread.sleep(1000);
}catch(InterruptedException ie){
System.exit(0);
}
tmt.start();
System.out.println("Files after 11 second--");
for(String fileName:fl.getFileList()){
System.out.println(fileName);
}
}
}
I am putting the timeout as 11 seconds(10+1).
This code is giving me a concurrent modification exception. Why should that occur considering only one thread accessing the fileList variable.
Considering that listing file is IO Bound will timer work concurrently.
I am not considering TimerTask/Executor as of now.
This does not really make sense if you stick to the old File API, since when you .listFiles(), the whole directory entries are swallowed into the array that is returned. That you iterate over it afterwards doesn't make the directory entry loading "lazy".
Where is does make sense is if you use the new java.nio.file API (Java 7+) -- and you should use that and drop File --, since Files.newDirectoryStream() does lazy load directory entries. (*)
This returns a DirectoryStream which is basically a lazy Iterable over the directory entries, except that it also implements Closeable. And therefore you can interrupt this, like in:
try (
final DirectoryStream<Path> entries = Files.newDirectoryStream(...);
) {
for (final Path entry: entries) {
if (Thread.currentThread().isInterrupted())
break;
// proceed with "entry"
}
}
One more reason to use that instead of .listFiles(): if the operation to get a DirectoryStream fails, you don't get null (!!) but an appropriate exception instead: AccessDeniedException, NotDirectoryException, NoSuchFileException, FileSystemLoopException (for filesystems with symlink support), etc etc.
Again: ditch File.
(*): at least for operating systems which support it (Linux has getdents() for instance) or, more generally, for all FileSystem implementations which support it
There are 3 threads in your code, file list thread, time out thread and main thread. The while loop executing in time out thread can not block code executing after tmt.start() line. So the fileList ArrayList(not thread safe) is accessed by main thread and file list thread simultaneously, this is why concurrent modification exception caused.
I am using this API to parse wikipedia dump available at
http://code.google.com/p/wikixmlj/
I am using my API as like this
Class wiki
{
public void parseWiki()
{
PageCallbackHandler handler = new WikiPageCallbackHandler()
WikiXMLSAXParser.parseWikipediaDump(filepath, handler )
}
}
Class WikiPageCallbackHandler implements PageCallbackHandler
{
//Override
//This is the callback
void process(WikiPage page)
{
String Text = page.GetText();
//Write this text into a file
.....
}
}
The issue is before all callbacks are done and I finish writing it into a file, the application is terminating and I am not getting all callbacks.
I want to know why this is happening and is there any way to hold my main thread, so that I get all my callbacks. Also, How would I know if I have got all my callbacks?
Thanks
Have you try using 'Semaphore' at Oracle Docs.
Here's an example use of Semaphore:
class wiki
{
public void parseWiki(){
// initialize Semaphore object
Semaphore semaphore = new Semaphore(1);
//pass it to callback handler so it can release semaphore latter
PageCallbackHandler handler = new WikiPageCallbackHandler(semaphore);
//This is the async operation, right?
WikiXMLSAXParser.parseWikipediaDump(filepath, handler );
//wait until a permit is available (when semaphore.release() is called)
semaphore.acquire(); //this throw InterruptedException, please handle it else where
}
}
class WikiPageCallbackHandler implements PageCallbackHandler
{
private Semaphore semaphore;
public WikiPageCallbackHandler(Semaphore semaphore){
this.semaphore = semaphore;
}
//Override
//This is the callback
void process(WikiPage page)
{
try{
String Text = page.GetText();
//Write this text into a file
.....
}finally{
semaphore.release();
}
}
}