Two BlockingQueue in the same endless loop? - java

I have a thread, that processes incomming messages (endless loop). For this, I use a BlockingQueue (Java), which works as quite nice. Now, I want to add a second processor in the same Class oder method. The problem now is, that in the endless loop i have this part
newIncomming = this.incommingProcessing.take();
This part blocks if the Queue is empty. I'm looking for a solution to process to queues in the same class. The second queue can only processed, it some data is coming in for the first Queue.
Is there a way to handle tow blocking queues in the same endless loop?

Either you need two threads or you need them to share the same blocking queue. (Or you need to use a different structure than blocking queue)

BlockingQueue is meant for multiple thread implementations. Instead, use a simple Queue. See this.

I am not sure what you are trying to do, but if you do not want the thread to block on the queue if it is empty, you can use BlockingQueue.peek() to first check if the queue is empty or not.

What I understand from your question I came up with the following
Code snippet
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package blockingqueues;
import java.io.BufferedReader;
import java.io.Console;
import java.io.InputStreamReader;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
/**
*
* #author alfred
*/
public class BlockingQueues {
private static String take(BlockingQueue<String> bq) {
try {
return bq.take();
} catch(InterruptedException ie) {
return null;
}
}
public static void main(String args[]) throws Exception {
final BlockingQueue<String> b1 = new LinkedBlockingQueue<String>();
final BlockingQueue<String> b2 = new LinkedBlockingQueue<String>();
ExecutorService es = Executors.newCachedThreadPool();
es.execute(new Runnable() {
public void run() {
while (true) {
String results = take(b1);
if (results == null) {
break;
}
System.out.println("first: " + results);
}
}
});
es.execute(new Runnable() {
public void run() {
while (true) {
String results = take(b2);
if (results == null) {
break;
}
System.out.println("second: " + results);
}
}
});
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in)
);
String input = null;
System.out.println("type x to quit.");
while (!"x".equals(input)) {
input = br.readLine();
if (input.startsWith("1 ")) {
// Add something to first blocking queue.
b1.add(input.substring(2));
} else if (input.startsWith("2 ")) {
// Add something to second blocking queue.
b2.add(input.substring(2));
}
}
es.shutdownNow();
es.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("bye!");
br.close();
}
}
Executing program:
You can enter text from console to add task to blockingqueue b1 or b2. If your console input starts with a 1 like for example input = "1 hello" then the b1 will process task(print first: hello) else if input starts with a 2 like for example input = "world" then b2 will print second: world.

Related

How to use Scanner as a pause?

I'm writing a program that is meant to run through loops uninterrupted, with a user option to pause at any time. I want to use Scanner as a means for the user to input what they want to do to pause the program, but instead the program pauses every time it loops through, and the user is forced to input something before the code continues. My code looks like this:
for (int i = 0; i < 10; i++)
{
String pause = scan.next()
{
if (pause.equals("pause")
{
//break mechanism
}
}
}
Any ideas for how I could use this with a temporary pause? I was thinking maybe it could be something like "if 3 seconds pass, continue" but I'm not sure that would work, or how to code it. Thanks for any help.
Maybe like this:
while(scan.hasNext()) {
String pause = scan.next();
if (pause.equals("pause"))
{
//stop
}
}
As far as i understood it, your program stops, when the for-loop is done. Now the while-loop will be done when there is no more input.
maybe I think that it helps you with your idea
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.generic;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Scanner;
/**
*
* #author wilso
*/
public class prueba {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
while (true) {
String pause = scan.next();
if (pause.toLowerCase().equals("pause")) {
System.out.println("Esperando quitar el modo pause");
pause = scan.next();
}
}
}
}
what I understood is this:
import java.util.Scanner;
public class Main
{
public static void main(String[] args) {
WorkerThread workerThread = new WorkerThread();
PausingThread pausingThread = new PausingThread(workerThread);
workerThread.start();
pausingThread.start();
}
}
class WorkerThread extends Thread{
#Override
public void run() {
while (true)
{
//Your work is being done
}
}
}
class PausingThread extends Thread{
WorkerThread workerThread;
PausingThread(WorkerThread thread){
this.workerThread = thread;
}
#Override
public void run() {
Scanner scan = new Scanner(System.in);
while (scan.next().equals("pause")){
try {
System.out.println("workerThread sleeping");
workerThread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
this will work...

Algorithm - execute task only for unique entries in queue, common entries should wait

We are creating a rest application. And we have an edge condition where parallel actions are not supported on same object.
For example :
Not supported in parallel
Request 1 for action XYZ for object A
Request 2 for action XYZ for object A
Request 3 for action ABC for object A
Supported in parallel
Request 1 for action XYZ for object A
Request 2 for action XYZ for object B
Request 3 for action ABC for object C
Now, the object count is not fixed. we can have n number of such objects.
I want that if a request for object A is under progress then other request for object A should wait for existing task on object A to get over.
But I am not able to figure out the algorithm for this purpose.
I could plan for below design but not able to figure out on how to use the locking since all objects can be different.
A queue which stores the entry for object A when request comes.
Entry gets deleted if response is sent
If an entry is already present, then wait for existing request to get over.
If entry not present, then execute immediately.
Now task on object A should not impact the task on object B. So they must accept unique locks.
And also, request cannot go standalone and be queued. Somehow I have to make the current thread sleep so that I can send response to user.
Can anyone guide here?
UPDATED based on comments from my original response
The ideal model for something like that would be using an actor system such as Akka.
But your comment states that this will happen in the context on a REST application where threads will be blocked already by request processing.
In this case, the idea would be using a per-object-guard such as:
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
public class ObjectGuard<K> {
private final ConcurrentMap<K, CountDownLatch> activeTasks = new ConcurrentHashMap<>();
public Guard guardFor(final K key) throws InterruptedException {
if (key == null) {
throw new NullPointerException("key cannot be null");
}
final CountDownLatch latch = new CountDownLatch(1);
while (true) {
final CountDownLatch currentOwner = activeTasks.putIfAbsent(key, latch);
if (currentOwner == null) {
break;
} else {
currentOwner.await();
}
}
return () -> {
activeTasks.remove(key);
latch.countDown();
};
}
public interface Guard extends AutoCloseable {
#Override
void close();
}
}
You would use it as follows:
class RequestProcessor {
private final ObjectGuard<String> perObjectGuard = new ObjectGuard<>();
public String process(String objectId, String op) throws InterruptedException {
// Only one thread per object id can be present at any given time
try (ObjectGuard.Guard ignore = perObjectGuard.guardFor(objectId)) {
String result = ... // compute response
}
}
}
If two concurrent calls to process are received for the same object id, only one will be processed, the others wait their turn to process a request on that object.
An object which executes requests serially is known as Actor. The most widely known java actor library is named Akka. The most simple (one page) actor implementation is my SimpleActor.java.
Signalling like juancn does in his answer is not my strong suit, so I made an even cruder solution using one Semaphore for signalling combined with a request-counter.
There is one lock involved (subjectsLock) which synchronizes everything at one point in time. The lock is required to ensure there are no memory leaks: since there can be any number of subjects (a.k.a. object identifiers in your question), cleanup is essential. And cleanup requires knowing when something can be removed and that is difficult to determine without a lock that brings everything to one known state at a certain point in time.
The test in the main-method in the code shown below is a bit hard to read, but it serves as a starting point for a demonstration of how the code works internally. The main logic is in the methods executeRequest, addSubject and removeSubject. If those three methods do not make sense, another solution should be used.
Stress-testing will have to determine if this solution is fast enough: it depends on the number of requests (per second) and the amount of time it takes to complete an action. If there are many requests and the action is short/fast, the (synchronization) overhead from the lock could be to high.
// package so;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.IntStream;
public class RequestQueue {
public static void main(String[] args) {
// Randomized test for "executeRequest" method below.
final int threadCount = 4;
ExecutorService threadPool = Executors.newFixedThreadPool(threadCount);
try {
final int requestCount = 100;
final RequestQueue rq = new RequestQueue();
final Random random = new Random();
IntStream.range(0, requestCount).forEach(i -> threadPool.execute(new Runnable() {
#Override
public void run() {
try {
String subject = "" + (char) (((int)'A') + random.nextInt(threadCount));
rq.executeRequest(subject, new SleepAction(i, subject, 50 + random.nextInt(5)));
} catch (Exception e) {
e.printStackTrace();
}
}
}));
sleep(100); // give threads a chance to start executing.
while (true) {
sleep(200);
List<String> subjects = rq.getSubjects();
System.out.println("Subjects: " + subjects);
if (subjects.isEmpty()) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
private Map<String, QueueLock> subjects = new LinkedHashMap<>();
// a fair ReentrantLock is a little bit slower but ensures everybody gets their turn in orderly fashion.
private final ReentrantLock subjectsLock = new ReentrantLock(true);
private class QueueLock {
// a fair Semaphore ensures all requests are executed in the order they arrived.
final Semaphore turn = new Semaphore(1, true);
final AtomicInteger requests = new AtomicInteger(1);
public String toString() { return "request: " + requests.get(); }
}
/**
* Allow all requests for different subjects to execute in parallel,
* execute actions for the same subject one after another.
* Calling thread runs the action (possibly after waiting a bit when an action for a subject is already in progress).
*/
public String executeRequest(String subject, Runnable action) throws InterruptedException {
QueueLock qlock = addSubject(subject);
try {
int requestsForSubject = qlock.requests.get();
if (requestsForSubject > 1) {
System.out.println(action.toString() + " waiting for turn " + requestsForSubject);
}
qlock.turn.acquire();
if (requestsForSubject > 1) {
System.out.println(action.toString() + " taking turn " + qlock.requests.get());
}
action.run();
} catch (Exception e) {
e.printStackTrace();
} finally {
removeSubject(subject);
}
return timeSinceStart() + " " + subject;
}
private QueueLock addSubject(String s) {
QueueLock qlock = null;
subjectsLock.lock();
try {
qlock = subjects.get(s);
if (qlock == null) {
qlock = new QueueLock();
subjects.put(s, qlock);
} else {
qlock.requests.incrementAndGet();
}
} finally {
subjectsLock.unlock();
}
return qlock;
}
private boolean removeSubject(String s) {
boolean removed = false;
subjectsLock.lock();
try {
QueueLock qlock = subjects.get(s);
if (qlock.requests.decrementAndGet() == 0) {
subjects.remove(s);
removed = true;
} else {
qlock.turn.release();
}
} finally {
subjectsLock.unlock();
}
return removed;
}
public List<String> getSubjects() {
List<String> subjectsBeingProcessed = new ArrayList<>();
subjectsLock.lock();
try {
// maintains insertion order, see https://stackoverflow.com/a/18929873/3080094
subjectsBeingProcessed.addAll(subjects.keySet());
} finally {
subjectsLock.unlock();
}
return subjectsBeingProcessed;
}
public static class SleepAction implements Runnable {
final int requestNumber;
final long sleepTime;
final String subject;
public SleepAction(int requestNumber, String subject, long sleepTime) {
this.requestNumber = requestNumber;
this.sleepTime = sleepTime;
this.subject = subject;
}
#Override
public void run() {
System.out.println(toString() + " sleeping for " + sleepTime);
sleep(sleepTime);
System.out.println(toString() + " done");
}
public String toString() {return timeSinceStart() + " " + subject + " [" + Thread.currentThread().getName() + "] " + String.format("%03d",requestNumber); }
}
public static final long START_TIME = System.currentTimeMillis();
public static String timeSinceStart() {
return String.format("%05d", (System.currentTimeMillis() - START_TIME));
}
public static void sleep(long milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

ExecutorService doens't work

I have problem using Executorservice
I implemented Consumer-Producer Pattern
Main
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(10000);
Thread producer = new Thread(new Producer(queue));
ExecutorService executorService = Executors.newFixedThreadPool(3);
Runnable consumer1 = new Consumer(queue);
Runnable consumer2 = new Consumer(queue);
Runnable consumer3 = new Consumer(queue);
producer.start();
executorService.submit(consumer1);
executorService.submit(consumer2);
executorService.submit(consumer3);
executorService.shutdown();
}
}
Producer
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class Producer implements Runnable{
public BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(10000);
public Producer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
public synchronized void run() {
for (int i=0; i<100; ++i) {
try {
//System.out.println("i = " + i);
queue.put(i);
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
}
Consumer
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class Consumer implements Runnable {
public BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(10000);
public Consumer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
public void run() {
while (true) {
try {
//queue.take(); // case 1
System.out.println(Thread.currentThread().getName() + " Consumer : " + queue.take()); // case 2
} catch (InterruptedException e) {
System.out.println(e);
}
if (queue.isEmpty()) {
break;
}
}
}
}
I wonder why (Consumer.java) case 1 is not working,
but case 2 is fine
It print noting and never stopping (This comment isn't good. Ignore it ㅠㅠ)
I just wonder, Why case 1 is not Stop.
Is there something in System.out.println or BlockingQueue?
(Poducer.java also. If i added print i in Producer.java then Throws InterruptedException)
May be I don't know java and thread well.
Please help me ;(
(My English isn't good, Sorry)
The fundamental problem here is that if the queue ever becomes empty just before the queue.take(), the consumer thread will block until something gets added to the queue. Since you do all the adding to the queue prior to starting the consumers, it is a matter of luck whether one of the consumers will get into a blocked state.
It appears that case 2 (with the console output) slows things down enough that no thread gets into this state. In case 1 processing is so fast that at least one thread finds itself blocked. When I ran your code I found thread 3 blocked, meaning that probably threads 1 and 2 consumed all entries in the queue before thread 3 even had a chance to get started.
If your usecase involves the queue being filled first by the Producer and then running the Consumer threads, you should use poll() instead of take() which will let you detect the condition of running out of elements.

Java program with multiple threads not working

So, I'm having a problem with a Gui i'm designing for a java app that renames all the files in a given directory to junk (Just for fun). This is the main block of code behind it all:
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
/**
* Class for renaming files to garbage names.
* All methods are static, hence private constructor.
* #author The Shadow Hacker
*/
public class RenameFiles {
private static int renamedFiles = 0;
private static int renamedFolders = 0;
public static char theChar = '#';
public static ArrayList<File> fileWhitelist = new ArrayList<>();
public static HashMap<File, File> revert = new HashMap<>();
public static int getRenamedFiles() {
return renamedFiles;
}
public static int getRenamedFolders() {
return renamedFolders;
}
/**
* All methods are static, hence private constructor.
*/
private RenameFiles() {
// Private constructor, nothing to do.
}
/**
* #param file The file to rename.
* #param renameTo The current value of the name to rename it to.
* #return A new value for renameTo.
*/
private static String renameFile(File file, String renameTo) {
for (File whitelistedFile : fileWhitelist) {
if (whitelistedFile.getAbsolutePath().equals(file.getAbsolutePath())) {
return renameTo;
}
}
if (new File(file.getParentFile().getAbsolutePath() + "/" + renameTo).exists()) {
renameTo += theChar;
renameFile(file, renameTo);
} else {
revert.put(new File(file.getParent() + "/" + renameTo), file);
file.renameTo(new File(file.getParent() + "/" + renameTo));
if (new File(file.getParent() + "/" + renameTo).isDirectory()) {
renamedFolders++;
} else {
renamedFiles++;
}
}
return renameTo;
}
/**
* TODO Add exception handling.
* #param dir The root directory.
* #throws NullPointerException if it can't open the dir
*/
public static void renameAllFiles(File dir) {
String hashtags = Character.toString(theChar);
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
renameAllFiles(file);
hashtags = renameFile(file, hashtags);
} else {
hashtags = renameFile(file, hashtags);
}
}
}
public static void renameAllFiles(String dir) {
renameAllFiles(new File(dir));
}
/**
* This uses the revert HashMap to change the files back to their orignal names,
* if the user decides he didn't want to change the names of the files later.
* #param dir The directory in which to search.
*/
public static void revert(File dir) {
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
revert(file);
}
revert.forEach((name, renameTo) -> {
if (file.getName().equals(name.getName())) {
file.renameTo(renameTo);
}
});
}
}
public static void revert(String dir) {
revert(new File(dir));
}
/**
* Saves the revert configs to a JSON file; can't use obj.writeJSONString(out)
* because a File's toString() method just calls getName(), and we want full
* paths.
* #param whereToSave The file to save the config to.
* #throws IOException
*/
#SuppressWarnings("unchecked")
public static void saveRevertConfigs(String whereToSave) throws IOException {
PrintWriter out = new PrintWriter(whereToSave);
JSONObject obj = new JSONObject();
revert.forEach((k, v) -> {
obj.put(k.getAbsolutePath(), v.getAbsolutePath());
});
out.write(obj.toJSONString());
out.close();
}
/**
* Warning - clears revert.
* Can't use obj.putAll(revert) because that puts the strings
* into revert, and we want Files.
* TODO Add exception handling.
* #param whereToLoad The path to the file to load.
* #throws ParseException If the file can't be read.
*/
#SuppressWarnings("unchecked")
public static void loadRevertConfigs(String whereToLoad) throws ParseException {
revert.clear();
((JSONObject) new JSONParser().parse(whereToLoad)).forEach((k, v) -> {
revert.put(new File((String) k), new File((String) v));
});
}
/**
* This static block is here because the program uses forEach
* loops, and we don't want the methods that call them to
* return errors.
*/
static {
if (!(System.getProperty("java.version").startsWith("1.8") || System.getProperty("java.version").startsWith("1.9"))) {
System.err.println("Must use java version 1.8 or above.");
System.exit(1);
}
}
/**
* Even though I made a gui for this, it still has a complete command-line interface
* because Reasons.
* #param argv[0] The folder to rename files in; defaults to the current directory.
* #throws IOException
*/
public static void main(String[] argv) throws IOException {
Scanner scanner = new Scanner(System.in);
String accept;
if (argv.length == 0) {
System.out.print("Are you sure you want to proceed? This could potentially damage your system! (y/n) : ");
accept = scanner.nextLine();
scanner.close();
if (!(accept.equalsIgnoreCase("y") || accept.equalsIgnoreCase("yes"))) {
System.exit(1);
}
renameAllFiles(System.getProperty("user.dir"));
} else if (argv.length == 1 && new File(argv[0]).exists()) {
System.out.print("Are you sure you want to proceed? This could potentially damage your system! (y/n) : ");
accept = scanner.nextLine();
scanner.close();
if (!(accept.equalsIgnoreCase("y") || accept.equalsIgnoreCase("yes"))) {
System.exit(1);
}
renameAllFiles(argv[0]);
} else {
System.out.println("Usage: renameAllFiles [\033[3mpath\033[0m]");
scanner.close();
System.exit(1);
}
System.out.println("Renamed " + (renamedFiles != 0 ? renamedFiles : "no") + " file" + (renamedFiles == 1 ? "" : "s")
+ " and " + (renamedFolders != 0 ? renamedFolders : "no") + " folder" + (renamedFolders == 1 ? "." : "s."));
}
}
As you can see, all of it's methods are static. Now here is my (Only partially completed) event handler class:
import java.io.File;
/**
* Seperate class for the gui event handlers.
* Mostly just calls methods from RenameFiles.
* Like RenameFiles, all methods are static.
* #author The Shadow Hacker
*/
public class EventHandlers {
private static Thread t;
/**
* The reason this is in a new thread is so we can check
* if it is done or not (For the 'cancel' option).
* #param dir The root directory used by RenameFiles.renameAllFiles.
*/
public static void start(File dir) {
t = new Thread(() -> {
RenameFiles.renameAllFiles(dir);
});
t.start();
}
/**
* #param dir The root directory used by RenameFiles.revert(dir).
* #throws InterruptedException
*/
public static void cancel(File dir) throws InterruptedException {
new Thread(() -> {
while (t.isAlive()) {
// Nothing to do; simply waiting for t to end.
}
RenameFiles.revert(dir);
}).start();
}
public static void main(String[] args) throws InterruptedException {
start(new File("rename"));
cancel(new File("rename"));
}
}
The problem I'm having is that when I run revert from the RenameFiles class it works fine, but while running it from the multithreaded (We don't want the handlers to have to wait for the method to finish before reacting to another button press) EventHandlers class, revert dosn't work. Does this have something to do with RenameFiles being a class with all static methods, or something else? Please help!
Edit: #Douglas, when I run:
import java.io.File;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Seperate class for the gui event handlers.
* Mostly just calls methods from RenameFiles.
* Like RenameFiles, all methods are static.
* #author The Shadow Hacker
*/
public class EventHandlers {
private static ExecutorService service = Executors.newSingleThreadExecutor();
private static volatile CountDownLatch latch;
/**
* The reason this is in a new thread is so we can check
* if it is done or not (For the 'cancel' option).
* #param dir The root directory used by RenameFiles.renameAllFiles.
*/
public static void start(File dir) {
latch = new CountDownLatch(1);
service.submit(() -> {
RenameFiles.renameAllFiles(dir);
latch.countDown();
});
}
/**
* #param dir The root directory used by RenameFiles.revert(dir).
* #throws InterruptedException
*/
public static void cancel(File dir) throws InterruptedException {
service.submit(() -> {
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
RenameFiles.revert(dir);
});
}
The program just runs forever, without terminating.
You have two major problems here.
First, you are sharing variables between threads. Default variable handling in Java has no guarantee that two threads will agree on what value any given variable has. You can fix this one by giving each variable the volatile modifier (note: this can decrease performance, which is why it's not default).
Second, you have no mechanism in place to guarantee anything about thread execution order. As written, it is entirely possible for EventHandlers.main to run cancel to completion before the renameAllFiles call even starts. It is also possible for the renaming to start, get paused by the thread scheduler, cancel run from beginning to end, and then renaming finish, or any of a bunch of other combinations. You attempted to do something about this with the t.isAlive() check, but your redundant creation of yet another Thread in main means there's no guarantee t is even initialized before the main thread gets there. It would be an unlikely but valid by the spec possibility for you to get a NullPointerException from that line.
This second problem is a much harder one to fix in general, and is the primary reason working with threads is infamously difficult. Fortunately this particular problem is a fairly simple case. Instead of looping forever on the isAlive() check, create a CountDownLatch when you start the thread, count it down when the thread finishes, and simply await() it in cancel. This will incidentally also solve the first problem at the same time without any need for volatile, because in addition to its scheduling coordination a CountDownLatch guarantees that any thread that awaited on it will see the results of everything done in any thread that counted it down.
So, long story short, steps to fix this:
Remove the new Thread in main and just call start directly. start creates a Thread itself, there's no need to nest that inside another Thread.
Replace the Thread t with a CountDownLatch.
In start, initialize the CountDownLatch with a count of 1.
In start, after initializing the CountDownLatch, get an ExecutorService by calling Executors.newSingleThreadExecutor(), and then submit the renameAllFiles call to it. Do this instead of using a Thread directly. Among other things, the specification guarantees that anything done before that will be visible as expected in the new thread, and I don't see any such guarantee in the documentation of Thread.start(). It's also got a lot more convenience and utility methods.
Inside what you submit to the ExecutorService, after the renaming, call countDown() on the latch.
After the submit, call shutdown() on the ExecutorService. This will prevent you from reusing the same one, but stops it from waiting indefinitely for reuse that will never happen.
In cancel, replace the while loop with a call to await() on the latch. In addition to the memory consistency guarantee, this will improve performance by letting the system thread scheduler handle the wait instead of spending CPU time on looping.
Additional changes will be needed if you want to account for multiple rename operations in the same run of the program.

Check that Files Execute Concurrently

I need to perform 2 tasks independently.
First Task
Once per minute it should check whether there is any file in a specific folder. If there is, it should add the names of the files to a queue.
This can be done as follows:
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class schedulerExample extends Thread{
public void checkFile()
{
System.out.println("checking whether file exist in folder");
}
public void getFiles()
{
System.out.println("getting the file names");
}
public void enqueueFiles()
{
System.out.println("add files to queue");
}
public static void main(String[] args) {
final schedulerExample obj = new schedulerExample();
ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1);
executor.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
obj.checkFile();
obj.getFiles();
obj.enqueueFiles();
}
}, 0, 1, TimeUnit.MINUTES);
}
}
Second Task
If the queue is empty , sleep for one minute or else process the file from the queue one-by-one.
public class processModel extends Thread{
public static void getQueueSize(int size)
{
System.out.println("getting queue size");
}
public void dequeue()
{
// dequeue the queue
System.out.println("dequeue");
}
public void processFile()
{
// process the file
System.out.println("process file");
}
public static void main(String[] args) {
final boolean flag = true;
final int size = 9;
final processModel obj = new processModel();
Thread t1 = new Thread(){
public void run()
{
while(flag)
{
obj.dequeue();
obj.processFile();
getQueueSize(size);
if(size == 0)
{
try
{
Thread.sleep(60000);
}
catch(InterruptedException e)
{
}
}
}
}
};
t1.start();
}
}
Now I need to do both in a single class concurrently. Is that possible?
One thread should be fetching the files once per minute. Another thread should execute files one-by-one.. if no files are there it waits for a minute and checks again. In the second method I have used an infinite loop -- instead of that, is there a way that I can perform things one-by-one?
You might want to consider using Callables with the java ExecutorService. This can be used to easily break up tasks and allow them to run concurrently. Beyond that, you can get a Future which will allow you to check the results at any time (or postpone if it's not done).
There is a great book about java and concurrency called "Concurrency in Practice."
Beyond that, Java 7 has new functionality to allow file listeners on directories. That might allow you to abstract this "check and loop" functionality.
Synchronize on the queue object when you get file from it and when you add file to it.
In the thread that reads, call wait() if the queue is empty.
In the thread that checks for new files, call notify() after you added the new file to the queue.
This is how it's usually done.
You should also prevent adding file that is being processed to the queue.

Categories