I am creating a Java application. On start up, my application will download all required files. My application will parse XML file and download files from the URL from XML files. I want my application download files "step by step" so i use FutureTask My problem is, FutureTask is not working for my application.
Here is some part of my code.
Startup.class
public void startDownloading()
{
Thread t = new Thread(new Runnable()
{
public void run()
{
downloader.startDownload();
}
});
t.run();
}
}
Downloader.class
private LibrariesDownloader ld;
private RDownloader rd;
public Downloader()
{
this.ld = new LibrariesDownloader(launcher);
this.rd = new RDownloader(launcher);
}
public void startDownload()
{
ExecutorService executor = Executors.newFixedThreadPool(2);
FutureTask<Void> libDownloader = new FutureTask<Void>(ld);
FutureTask<Void> resDownloader = new FutureTask<Void>(rd);
executor.execute(libDownloader);
if(libDownloader.isDone())
{
executor.execute(resDownloader);
}
}
LibrariesDownloader.class(& RDownloader.class(Code almost the same, only URL is different))
public class LibrariesDownloader implements Callable<Void>
{
private Proxy proxy = Proxy.NO_PROXY;
#Override
public Void call() throws Exception
{
try
{
URL resourceUrl = new URL("http://www.exmaple.com/libraries.xml");
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(resourceUrl.openConnection(proxy).getInputStream());
NodeList nodeLst = doc.getElementsByTagName("Content");
for (int i = 0; i < nodeLst.getLength(); i++)
{
Node node = nodeLst.item(i);
if (node.getNodeType() == 1)
{
Element element = (Element)node;
String key = element.getElementsByTagName("Key").item(0).getChildNodes().item(0).getNodeValue();
final File path = new File("C://test/", key);
final String url = "http://www.exmaple.com/dl/" + key;
final String fileName = key;
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>()
{
#Override
protected Void doInBackground() throws Exception
{
try
{
URL fileURL = new URL(url);
org.apache.commons.io.FileUtils.copyURLToFile(fileURL, path);
}
catch(Exception e)
{
URL redownloadURL = new URL("http://www.example.com/dl/" + fileName);
File p = new File("C://test/", fileName);
org.apache.commons.io.FileUtils.copyURLToFile(redownloadURL, p);
}
return null;
}
#Override
public void done()
{
System.out.println(fileName + " had downloaded successfully");
}
};
worker.execute();
}
}
}
catch(Exception e)
{
launcher.println("An error was found when trying to download libraries file " + e);
}
return null;
}
}
There is ton of <Key></Key> in my XML file. My application can execute LibrariesDownloader and download all libraries files. After all libraries files had downloaded, my application just stop there. It will not execute RDownloader.
Is that any code wrong in my application? Thanks for helping me.
You start a new thread with
t.run();
It should be t.start(). The thread scheduler calls the run().
You probably want a busy/wait loop or a timeout for LibrariesDownloader
if(libDownloader.isDone())
{
executor.execute(resDownloader);
}
should be
Future<?> future = executor.submit(libDownloader);
while (!future.isDone()) {
//bad spin wait
}
executor.execute(resDownloader);
Better still, make a single ThreadPoolExecutor with Executors.newSingleThreadExecutor() or the more robust Executors.newFixedThreadPool(1) and submit both of them. The 2nd task will be queued.
The code snippet would look like
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.execute(libDownloader);
executor.execute(resDownloader);
Related
I'm reading about thread safety and synchronized keyword, but I'm stuck figuring out how it's implemented correctly.
I have a scenario where Thread A saves data to a Buffer while Thread B reads the data and saves it to the database.
How can I achieve thread safety with the following code?
By thread safety I mean Thread B wont start until Thread A finished it's job and same applies to Thread A.
public class Main {
public static void main(String args[]) throws InterruptedException {
LinkedBlockingQueue<Document> queue = new LinkedBlockingQueue<>();
ProducerThread mProducer = new ProducerThread(queue);
ConsumerThread mConsumer = new ConsumerThread(queue);
new Thread(mProducer).start();
new Thread(mConsumer).start();
}
}
--
public class ProducerThread implements Runnable {
private LinkedBlockingQueue<Document> queue;
public ProducerThread(LinkedBlockingQueue<Document> queue) {
this.queue = queue;
}
#Override
public void run() {
while(true) {
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
Document document = new Document("timeAdded", timestamp);
try {
queue.put(document);
System.out.println("Document added " + document.toString());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
--
public class ConsumerThread implements Runnable {
private LinkedBlockingQueue<Document> queue;
private Database mDatabase;
public ConsumerThread(LinkedBlockingQueue<Document> queue) {
this.queue = queue;
}
#Override
public void run() {
try {
Document doc;
mDatabase = Database.getInstance();
if (Client.isAlive()) {
while (queue.take() != null) {
mDatabase.insert(queue.take());
// Thread.sleep(10);
System.out.println("Document consumed " + queue.take().toString());
if (!Client.isAlive()) {
wait();
Client.reconnect();
}
}
} else {
wait();
}
} catch(InterruptedException | IllegalMonitorStateException e){
e.printStackTrace();
}
}
}
I get the following output
> Document added{{timeAdded=2018-04-22 13:20:27.88}}
> Document{{timeAdded=2018-04-22 13:20:27.88}} Document added
> Document{{timeAdded=2018-04-22 13:20:28.881}} Document added
> Document{{timeAdded=2018-04-22 13:20:29.882}} Document added
> Document{{timeAdded=2018-04-22 13:20:30.882}} Consumed
> Document{{timeAdded=2018-04-22 13:20:30.882}} Document added
> Document{{timeAdded=2018-04-22 13:20:31.883}} Document added
> Document{{timeAdded=2018-04-22 13:20:32.883}} Consumed
> Document{{timeAdded=2018-04-22 13:20:33.884}} Document added
> Document{{timeAdded=2018-04-22 13:20:33.884}} Document added
> Document{{timeAdded=2018-04-22 13:20:34.885}} Document added
> Document{{timeAdded=2018-04-22 13:20:35.885}} Document added
> Document{{timeAdded=2018-04-22 13:20:36.886}} Consumed
> Document{{timeAdded=2018-04-22 13:20:36.886}} Document added
I don't know if this helps, but I would write a third class called ProductionProcess or something like that...
Short additional explanation: The ProductionClass holds the queue which stores the single Document objects. The Producer thread starts to "produce" objects as long as the queue (At the moment size of 10) is full. Whenever a slot in this queue gets free because the Consumer thread removed a Document object. The Producer thread receives a signal and starts "producing" Document objects again until the queue is full. The complete source code should be thread-safe.
public class ProductionProcess
{
private static final int CAPACITY;
private final Queue QUEUE;
private final Lock LOCK;
private final Condition BUFFER_FULL;
private final Condition BUFFER_EMPTY;
static
{
CAPACITY = 10;
}
ProductionProcess()
{
this.QUEUE = new LinkedList <Document> ();
this.LOCK = new ReentrantLock();
this.BUFFER_FULL = this.LOCK.newCondition();
this.BUFFER_EMPTY = this.LOCK.newCondition();
}
public void produce() throws InterruptedException
{
this.LOCK.lock();
try
{
while(ProductionProcess.CAPACITY == this.QUEUE.size())
{
System.out.println(Thread.currentThread().getName() + " : Buffer is full, waiting!");
this.BUFFER_FULL.await();
}
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
Document document = new Document("timeAdded", timestamp);
if(true == this.QUEUE.offer(document))
{
System.out.printf("Added to queue: " + document);
this.BUFFER_EMPTY.signalAll();
}
}
finally
{
this.LOCK.unlock();
}
}
public void receive() throws InterruptedException
{
this.LOCK.lock();
try
{
Database mDatabase = Database.getInstance();
while(0 == this.QUEUE.size())
{
System.out.println(Thread.currentThread().getName() + " : Buffer is empty, waiting!");
this.BUFFER_EMPTY.await();
}
Document mDocument = (Document) this.QUEUE.poll());
if(null != mDocument)
{
mDatabase.insert(mDocument);
System.out.printf("Consumed from queue: " + document);
System.out.println(Thread.currentThread().getName() + " : Signalling that buffer may be empty now");
this.BUFFER_FULL.signalAll();
}
}
finally
{
this.LOCK.unlock();
}
}
}
After that use it like this...
ProductionProcess process = new ProductionProcess();
Runnable runnableProducer = new Runnable() {
#Override public void run()
{
while(true)
{
try
{
process.produce();
Thread.sleep(1000);
}
catch(InterruptedException exc)
{
exc.printStackTrace();
}
}
}
}
Runnable runnableConsumer = new Runnable() {
#Override public void run()
{
while(true)
{
try
{
process.receive();
Thread.sleep(1000);
}
catch(InterruptedException exc)
{
exc.printStackTrace();
}
}
}
}
new Thread(runnableProducer).start();
new Thread(runnableConsumer).start();
I don't test it extensive but it should work. If it doesn't work just comment it...
Moreover its not my code if you can speak german watch this link.
The code below will make it more clear:
public static String TCMResponse(String params, final Context c) {
final String url = "https://115.248.161.106/ois/API/android/" + params;
new Thread(new Runnable() {
#Override
public void run() {
String response="";
try {
Document doc = Jsoup.connect(url).validateTLSCertificates(false).timeout(6000).get();
response = doc.text();
}
catch (IOException e) {
Log.d("Err","External OIS not reachable!");
}
// I want to return 'response' here, for the TCMResponse()
}
}).start();
}
So as you can see from the code, there is a function, TCMResponse() which takes the parameters of the url which i pass, and it does web scraping, i know all these can be done using volley/ JSONParser easily. But i am just experimenting, how to parse using web scraping.
So after the page is scraped, i need that function to return the response of the scraped page,
I've used Callable with executor service, but it again freezes the thread..
Have a look on what i've done:
public static String TCMResponse(String params, final Activity act) {
StrictMode.ThreadPolicy policy = new
StrictMode.ThreadPolicy.Builder()
.permitAll().build();
StrictMode.setThreadPolicy(policy);
final String url = "https://115.248.161.106/ois/API/android/" + params;
response="";
class MyBgThread implements Callable<String>
{
#Override
public String call() throws Exception {
try{
Document doc = Jsoup.connect(url).validateTLSCertificates(false).timeout(6000).get();
return doc.text();
}catch (Exception e)
{
Log.d("Exception",e.toString());
Snackbar.with(act, null)
.type(Type.ERROR)
.message("Something got wrong!")
.duration(Duration.LONG)
.show();
return "{'auth':'false'}";
}
}
}
Callable<String> worker = new MyBgThread();
ExecutorService ex = Executors.newSingleThreadExecutor();
Future<String> future = ex.submit(worker);
try{
response = future.get();
}catch(Exception e)
{
Log.d("Thread Ex",e+"");
}
ex.shutdown();
return response;
}
The main thread gets blocked because of your call to Future::get().
From the docs:
Waits if necessary for the computation to complete, and then retrieves its result.
which means; if the task Thread has not yet finished, the current Thread will wait until it returns a result.
I can see another problem in your code: you are showing a Snackbar, which is a UI component, in a Thread that is not the UI Thread.
Since you are working on Android, I would definitely use an AsyncTask, perform the expensive call in doInBackground(), then update the UI in onPostExecute().
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.
This question already has answers here:
How to wait for all threads to finish, using ExecutorService?
(27 answers)
Closed 8 years ago.
Please have a look at the following code.
public class BigFileWholeProcessor {
private static final int NUMBER_OF_THREADS = 2;
public void processFile(String fileName) {
BlockingQueue<String> fileContent = new LinkedBlockingQueue<String>();
BigFileReader bigFileReader = new BigFileReader(fileName, fileContent);
BigFileProcessor bigFileProcessor = new BigFileProcessor(fileContent);
ExecutorService es = Executors.newFixedThreadPool(NUMBER_OF_THREADS);
es.execute(bigFileReader);
es.execute(bigFileProcessor);
es.shutdown();
if(es.isTerminated())
{
System.out.println("Completed Work");
}
}
}
public class BigFileReader implements Runnable {
private final String fileName;
int a = 0;
public static final String SENTINEL = "SENTINEL";
private final BlockingQueue<String> linesRead;
public BigFileReader(String fileName, BlockingQueue<String> linesRead) {
this.fileName = fileName;
this.linesRead = linesRead;
}
#Override
public void run() {
try {
//since it is a sample, I avoid the manage of how many lines you have read
//and that stuff, but it should not be complicated to accomplish
BufferedReader br = new BufferedReader(new FileReader(new File("E:/Amazon HashFile/Hash.txt")));
String str = "";
while((str=br.readLine())!=null)
{
linesRead.put(str);
System.out.println(a);
a++;
}
linesRead.put(SENTINEL);
} catch (Exception ex) {
ex.printStackTrace();
}
System.out.println("Completed");
}
}
public class BigFileProcessor implements Runnable {
private final BlockingQueue<String> linesToProcess;
public BigFileProcessor (BlockingQueue<String> linesToProcess) {
this.linesToProcess = linesToProcess;
}
#Override
public void run() {
String line = "";
try {
while ( (line = linesToProcess.take()) != null) {
//do what you want/need to process this line...
if(line==BigFileReader.SENTINEL)
{
break;
}
String [] pieces = line.split("(...)/g");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I want to print the text "completed work" in BigFileWholeProcessor once all the thread work is done. But instead, it is not getting printed. Why is this? How to identify that all the threads are done and need printing?
shutdown() only signal ES to shutdown, you need
awaitTermination(long timeout, TimeUnit unit)
before print message
Use submit() method instead of execute(). The get() method can be used if you want to wait for the thread to finish at any point of time. Read documentation on use of Future object for further details.
ExecutorService es = Executors.newFixedThreadPool(2);
Future<?> f = es.submit(new Thread(new TestRun()));
f.get(); // Wait for result... (i.e similar to `join()` in this case)
es.shutdown(); // Shutdown ExecutorService
System.out.println("Done.");
I have defined a TestRun class implementing Runnable, not shown here. The Future object makes more sense in other scenarios.
This question already has answers here:
How to run a background task in a servlet based web application?
(5 answers)
Closed 7 years ago.
EDIT:
The current code is the working solution, the one which does not block the application, it
incorporates the suggestion made in the approved answer.
I want a background thread to download an MS Access database continuously, while my tomcat 7 web application is running, the thread does download the database, however it seems to block my application's startup as I'm unable to access any page from the service, this is the code that I'm using:
public class DatabaseUpdater implements ServletContextListener {
private Thread thread = null;
private final Runnable updater = new Runnable() {
private boolean hasExpired(File mdbFile) throws IOException {
if (!mdbFile.exists())
return true;
Long ttl = Long.parseLong(Configuration.getValueForOS("db.http-expiration"));
Date now = new Date();
Date fileDate = new Date(mdbFile.lastModified());
return (now.getTime() - fileDate.getTime()) > ttl;
}
#Override
public void run() {
while (true) {
if (Thread.currentThread().isInterrupted())
throw new RuntimeException("Application Shutdown");
try {
String databases[] = new String[]{"database1", "database2"};
for (String database : databases) {
String fileName = database + "." + StringUtil.randomString(8) + ".mdb";
String fileLocation = Configuration.getValueForOS("db.path");
File mdbFile = new File(fileLocation, fileName);
File currentDatabaseFile = new File(fileLocation, database + ".mdb");
if (hasExpired(currentDatabaseFile)) {
URL url = new URL(Configuration.getValueForOS("db.url." + database));
InputStream in = url.openConnection().getInputStream();
OutputStream out = new FileOutputStream(mdbFile);
FileUtil.streamBridge(in, out);
FileUtil.close(in, out);
while (currentDatabaseFile.exists() && !currentDatabaseFile.delete()) ;
while (!mdbFile.renameTo(currentDatabaseFile)) ;
}
}
// Put the thread to sleep so the other threads do not starve
Thread.sleep(Long.parseLong(
Configuration.getValueForOS("db.http-expiration"));
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
};
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
this.thread = new Thread(updater);
thread.start();
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
if (this.thread.isAlive())
this.thread.interrupt();
}
}
What could be causing?
I based my implementation on this question: Background Thread for a Tomcat servlet app
Given that your code loops forever, you're probably starving all the other threads in the VM. Try sleeping the thread once in a while.