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.
Related
So I've created a program, trying to display the dangers of using shared variables, so I have 3 classes the main called DangersOfSharedVariables and an Incrementer and Decrementer class.
So the idea is to have two threads running at once, both calling their respected methods, so the Decrementer class will call the decrementShared() method in the main and the Incrementer class will call the incrementShared() method in the main.
Here's the main method:
/*
* 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 dangersofsharedvariables;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
*/
public class DangersOfSharedVariables {
/**
* #param args the command line arguments
*/
private static int sharedValue =0;
private static int numberOfCycles = 2000000000;
public static void main(String[] args) {
// TODO code application logic here
Incrementer in = new Incrementer(numberOfCycles);
Decrementer de = new Decrementer(numberOfCycles);
Semaphore sem = new Semaphore(1);
in.start();
try {
in.join();
} catch (InterruptedException ex) {}
de.start();
try {
de.join();
} catch (InterruptedException ex) {}
System.out.println(sharedValue);
}
public void decrementShared(){
sharedValue -=10;
}
public void incrementShared(){
sharedValue +=10;
}
}
Here's the Incrementer class
/*
* 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 dangersofsharedvariables;
/**
*
*
*/
public class Incrementer extends Thread {
private int numberOfIncrements;
public Incrementer(int numberOfIncrements) {
this.numberOfIncrements = numberOfIncrements;
}
#Override
public void run() {
DangersOfSharedVariables in = new DangersOfSharedVariables();
for(int i = 0; i < numberOfIncrements; i++){
in.incrementShared();
}
}
}
Decrementer Class:
/*
* 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 dangersofsharedvariables;
/**
*
*
*/
public class Decrementer extends Thread {
private int numberOfDecrements;
public Decrementer(int numberOfDecrements){
this.numberOfDecrements = numberOfDecrements;
}
#Override
public void run(){
DangersOfSharedVariables d = new DangersOfSharedVariables();
for(int i = 0; i < numberOfDecrements; i++){
d.decrementShared();
}
}
}
I was googling and a more secure way to do this would be with the use of a Sempaphore class. So I took it upon myself to play around with a semaphore template I found, but am unsure as to how i'd implement it.
Semaphore Class:
package dangersofsharedvariables;
public class Semaphore {
// *************************************************************
// Class properties.
// Allow for both counting or mutex semaphores.
private int count;
// *************************************************************
// Constructor
public Semaphore(int n) {
count = n;
}
// *************************************************************
// Public class methods.
// Only the standard up and down operators are allowed.
public synchronized void down() {
while (count == 0) {
try {
wait(); // Blocking call.
} catch (InterruptedException exception) {
exception.printStackTrace();
}
}
count--;
}
public synchronized void up() {
count++;
notify();
}
}
Based on your query, following is a brief description about semephore data structures. Semaphores are useful in solving a variety of synchronised problems. The concept has been introduced by Dijkstra(1968) where he introduced the idea of semaphores as part of the operating system in order to synchronise processes with each other and with hardware.
The structure of a typical semaphore involves 4 stages:
Non-critical region
Entry protocol
Critical region
Exit protocol
The non-critical region is any code which can be carried out concurrently by 2-n threads.
The entry protocol is the code which must be executed by a process prior to entering a critical region. It is designed to prevent the process from entering the critical region if another process is already using shared resources.
The critical region is the section of code in which a shared resource is being accessed.
The exit protocol is the code that the process must execute immediately on completion of its critical region.
Semaphores can be put to different uses:
for mutual exclusive access to a single shared resource, in which case the semaphore is called a binary semaphore
to protect access to multiple instances of a resource (a counting semaphore)
to synchronise two processes (a blocking semaphore)
The versatility of the semaphore mechanism is achieved through correct initialisation.
For demonstration purposes please consult example below which showcases the most simple binary semaphore implementation:
Semaphore:
package BinarySemaphore;
public class Semaphore{
private static Semaphore semaphore;
private static int resource = 1;
private Semaphore(){}
public synchronized void increment(){
while(isAvailable()){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
resource += 1;
report();
this.notifyAll();
}
public synchronized void decrement(){
while(!isAvailable()){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
resource -= 1;
report();
this.notifyAll();
}
public synchronized final static boolean isAvailable(){
return resource == 1 ? true : false;
}
public synchronized final static void report(){
System.out.println("Resource value: " + resource);
}
public final static Semaphore getInstance(){
if(semaphore == null){
semaphore = new Semaphore();
}
return semaphore;
}
}
Incrementer:
package semaphore;
import BinarySemaphore.Semaphore;
public class Incrementer implements Runnable{
private static Semaphore semaphore = null;
public Incrementer(Semaphore s){
semaphore = s;
}
#Override
public void run() {
for(int i = 0; i < 10; i++){
System.out.println("Incrementing...");
semaphore.increment();
}
}
}
Decrementer:
package semaphore;
import BinarySemaphore.Semaphore;
public class Decrementer implements Runnable{
private static Semaphore semaphore = null;
public Decrementer(Semaphore s) {
semaphore = s;
}
#Override
public void run() {
for(int i = 0; i < 10; i++){
System.out.println("Decrementing...");
semaphore.decrement();
}
}
}
Main:
package semaphore;
import BinarySemaphore.Semaphore;
public class Main {
public static void main(String[] args){
Thread iIncrement = new Thread(new Incrementer(Semaphore.getInstance()));
Thread iDecrement = new Thread(new Decrementer(Semaphore.getInstance()));
iIncrement.start();
iDecrement.start();
}
}
Output:
Decrementing...
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Resource value: 1
The name for what you want is "mutex" which is short for "Mutual Exclusion". A mutex is a block of code that can only be executed by one thread at a time.
The Java language statement synchronized (foo) { ... } implements mutual exclusion. foo is an expression that yields up some object (sometimes called the lock object), and ... are the statements to be protected. The Java language guarantees that no two threads will be allowed to synchronize the same lock object at the same time.
Semaphore can be used to provide mutual exclusion, but it is more cumbersome, and it's antiquated.
Semaphore was invented before computers had hardware primitives for thread synchronization. It was supposed to be the "primitive" operation upon which other synchronization constructs (e.g., mutexes) could be built.
Today, the Java implementation of Semaphore actually is built on top of the same hardware primitives as the synchronized statement.
My task here is to perform unzip operation using multiple threads. I did it with following structure Way.
// A class for Unzipping files
public class UnzipClass extends Thread(){
private String zipfile;
private Thread t;
public UnzipClass(String zipFile){
this.zipFile = zipFile;
}
public String getZipFile() {
return zipFile;
}
public void setZipFile(String zipFile) {
this.zipFile = zipFile;
}
public void run() {
try {
unzipFolder(this.getZipFile());
} catch (IOException ex) {
Logger.getLogger(Unzipper.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void start(String filename){
if (t == null){
t = new Thread(this,filename);
t.start();
}
}
public unzipFolder(String zipFile) throws ZipException, IOException
// Here is the Unzip Method
}
}
// Now I am calling this class from another class
public static void main(){
Thread t1 = new UnzipClass("filename1");
t1.start();
if(!(t1.isAlive())){
logEvent("Unzip Complete");
}
// Similarly I have Thread t2 with another file name
}
The above code works perfect and unzips the files but I have following problems.
I wanted to use implements Runnable , but I cannot use it because I did not find a way to pass variable(Filename) to another class which implements Runnable and do it. Literally: How to implement Runnable instead of extends Thread`
Using above method, How can I detect if the unzip process has been completed. To be specific how to stop the thread when the file unzip process is completed`.
Any sort of hint or solution would be really great.
Thanks in advance.
1.change
public class UnzipClass extends Thread
into
public class UnzipClass implements Runnable
and use
Runnable t1 = new UnzipClass("filename1");
to create the thread.
2.
use a while loop here
while((t1.isAlive())){
logEvent("Unziping...");
}
logEvent("Unzip Complete");
but using a flag like boolean isComplete in the UnzipClass will me more effective. like
in class UnzipClass add
private boolean complete=false;
then,
public void run() {
try {
unzipFolder(this.getZipFile());
complete=true;
} catch (IOException ex) {
Logger.getLogger(Unzipper.class.getName()).log(Level.SEVERE, null, ex);
}
}
//simple getter.
public boolean isComplete()
{
return this.complete;
}
in main...
while(!t1.isComplete()){
logEvent("Unziping...");
}
logEvent("Unzip Complete");
Just change extends Thread to implements Runnable.
While creating new thread, you will do
Thread t1 = new Thread(new UnzipClass("filename1"));
Instead of
Thread t1 = new UnzipClass("filename1");
As you want to unzip couple files simultaniously, try using ExecutorService for that. You can submit Runnable taks to be executed by thread pool - this way, you will reuse already existing threads.
Check Executors and ExecutorService
Please, check this solution.
It uses Java 8 features, but it can be easily upgraded to be used with Java 5 / 6 / 7 (and external library, like Apache Commons or Guava).
/**
* File unzipping service
*/
public class Unzipper {
/**
* Default number of threads
*/
private static byte DEFAULT_THREADS_COUNT = 5;
/**
* Completion handler
*/
private Consumer onComplete;
/**
* Unzipping tasks
*/
private Collection<File> unzippingTasks = new LinkedList<>();
/**
* Add task for unzipping file
*
* #param file Path to file to be unzipped
* #return upgraded <code>this</code> instance
*/
public Unzipper unzip(String file) {
//check validity of 'file' string: non-null and non-empty
//check that file pointed by 'file' exists
unzippingTasks.add(new File(file));
return this;
}
/**
* Add unzipping completion handler
*
* #param onComplete Unzipping completion handler
* #return upgraded <code>this</code> instance
*/
public Unzipper onComplete(Consumer onComplete) {
//check validity of 'onComplete' object: non-null
this.onComplete = onComplete;
return this;
}
/**
* Run files unzipping (with default number of threads)
*/
public void run() {
run(DEFAULT_THREADS_COUNT);
}
/**
* Run files unzipping
*
* #param threads Number of parallel threads
*/
public void run(byte threads) {
//check validity of 'threads' argument: non-negative and non-zero
//check that we have at least one 'unzipping' task
if(unzippingTasks.isEmpty()) {
//output to log that unzipping tasks list is empty
return;
}
CountDownLatch latch = new CountDownLatch(threads);
Executor executor = Executors.newFixedThreadPool(threads + 1); //we are not blocking in 'run' method, so we should create extra thread to wait for all tasks completion
for(File file: unzippingTasks) {
executor.execute(() -> {
//unzip file
latch.release();
});
}
executor.execute(() -> {
latch.await(); //wait for all unzipping tasks completion
if(onComplete) //you can use 'optional' here instead
onComplete.accept(null);
});
executor.shutdown();
}
}
....
//Usage example
new Unzipper()
.unzip("<path-to-some-file>")
.unzip("<path-to-another-file>")
.unzip("<path-to-some-another-file>")
.onComplete(() -> {
//make you log output
})
.run();
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipException;
public class UnzipClass {
// Now I am calling this class from another class
public static void main() {
Thread t1 = new Thread(new UnzipClassRunner("filename1"));
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class UnzipClassRunner implements Runnable {
private String zipfile;
public UnzipClassRunner(String zipFile) {
this.zipfile = zipFile;
}
public void run() {
try {
unzipFolder(zipfile);
} catch (IOException ex) {
Logger.getLogger(Unzipper.class.getName()).log(Level.SEVERE, null,
ex);
}
}
public void unzipFolder(String zipFile) throws ZipException, IOException {
//
}
}
After spending lots of time with threadpool concepts and by reading different codes on numbers of blogs and posting questions on Stackoverflow.com, now I got clear image of this concept. But in the meanwhile, I found some doubts in code.
When pool.assign(new TestWorkerThread()); executes in TestThreadPool Class, it calls
done.workerBegin(); method that is in Done Class, where it increments _activeThreads variable. But what I thinks is, LOGICALLY that is not correct because if number of threads are less(in this case 2) than number of tasks (given in TestThreadPool Class)(in this case 5), it increments _activeThreads (i.e., _activeThreads = 5) counts unnecessarily.
What _started variable does in Done class?
How waitDone() and waitBegin() (in Done Class ) performs their functioning? (It is good if you explain these two methods step by step.)
Code is as follows. I am arranging the codes according to its flow.
TestThreadPool Class :-
package hitesh;
/**
*
* #author jhamb
*/
public class TestThreadPool {
public static void main(String args[]) throws InterruptedException
{
ThreadPool pool = new ThreadPool(2);
for (int i = 1;i <= 5;i++) {
pool.assign(new TestWorkerThread());
}
System.out.println("All tasks are assigned");
pool.complete();
System.out.println("All tasks are done.");
}
}
TestWorkerThread Class :-
package hitesh;
/**
*
* #author jhamb
*/
/**
* This class shows an example worker thread that can
* be used with the thread pool. It demonstrates the main
* points that should be included in any worker thread. Use
* this as a starting point for your own threads.
*/
public class TestWorkerThread implements Runnable {
static private int count = 0;
private int taskNumber;
protected Done done;
/**
*
* #param done
*/
TestWorkerThread()
{
count++;
taskNumber = count;
//System.out.println("tasknumber ---> " + taskNumber);
}
public void run()
{
System.out.println("TWT run starts --> " + this.toString());
for (int i=0;i <= 100;i += 25) {
System.out.println("Task number: " + taskNumber +
",percent complete = " + i );
try {
Thread.sleep((int)(Math.random()*500));
} catch (InterruptedException e) {
}
}
System.out.println("task for thread --> " + this.toString() + " completed");
}
}
ThreadPool Class :-
package hitesh;
/**
*
* #author jhamb
*/
import java.util.*;
/*
* This is the main class for the thread pool. You should
* create an instance of this class and assign tasks to it.
*/
public class ThreadPool {
protected Thread threads[] = null;
Collection assignments = new ArrayList(3);
protected Done done = new Done();
public ThreadPool(int size) throws InterruptedException
{
threads = new WorkerThread[size];
for (int i=0;i<threads.length;i++) {
threads[i] = new WorkerThread(this);
threads[i].start();
System.out.println ("thread " + i + " started");
threads[i].sleep(1000);
}
}
public synchronized void assign(Runnable r)
{
done.workerBegin();
assignments.add(r);
System.out.println("Collection size ---> " + assignments.size() + " Thread can work on this");
notify();
}
public synchronized Runnable getAssignment()
{
try {
while ( !assignments.iterator().hasNext() )
wait();
Runnable r = (Runnable)assignments.iterator().next();
assignments.remove(r);
return r;
} catch (InterruptedException e) {
done.workerEnd();
return null;
}
}
public void complete()
{
done.waitBegin();
done.waitDone();
}
}
WorkerThread Class :-
package hitesh;
import java.util.*;
/**
*
* #author jhamb
*/
/**
* The worker threads that make up the thread pool.
*/
class WorkerThread extends Thread {
/**
* True if this thread is currently processing.
*/
public boolean busy;
/**
* The thread pool that this object belongs to.
*/
public ThreadPool owner;
/**
* The constructor.
*
* #param o the thread pool
*/
WorkerThread(ThreadPool o)
{
owner = o;
}
/**
* Scan for and execute tasks.
*/
//#Override
public void run()
{
System.out.println("Threads name : "+ this.getName() + " working.....");
Runnable target = null;
do {
System.out.println("enter in do while " + this.getName() );
target = owner.getAssignment();
System.out.println("GetAssignment k aage aa gya mai " + target);
if (target!=null) {
target.run();
//target.
owner.done.workerEnd();
}
} while (target!=null);
System.out.println("do while finishes for "+ this.getName());
}
}
Done Class :-
package hitesh;
/**
*
* #author jhamb
*/
/**
*
* This is a thread pool for Java, it is
* simple to use and gets the job done. This program and
* all supporting files are distributed under the Limited
* GNU Public License (LGPL, http://www.gnu.org).
*
* This is a very simple object that
* allows the TheadPool to determine when
* it is done. This object implements
* a simple lock that the ThreadPool class
* can wait on to determine completion.
* Done is defined as the ThreadPool having
* no more work to complete.
*
* Copyright 2001 by Jeff Heaton
*
* #author Jeff Heaton (http://www.jeffheaton.com)
* #version 1.0
*/
public class Done {
/**
* The number of Worker object
* threads that are currently working
* on something.
*/
private int _activeThreads = 0;
/**
* This boolean keeps track of if
* the very first thread has started
* or not. This prevents this object
* from falsely reporting that the ThreadPool
* is done, just because the first thread
* has not yet started.
*/
private boolean _started = false;
/**
* This method can be called to block
* the current thread until the ThreadPool
* is done.
*/
synchronized public void waitDone()
{
try {
while ( _activeThreads>0 ) {
wait();
}
} catch ( InterruptedException e ) {
}
}
/**
* Called to wait for the first thread to
* start. Once this method returns the
* process has begun.
*/
synchronized public void waitBegin()
{
try {
while ( !_started ) {
wait();
}
} catch ( InterruptedException e ) {
}
}
/**
* Called by a Worker object
* to indicate that it has begun
* working on a workload.
*/
synchronized public void workerBegin()
{
_activeThreads++;
_started = true;
notify();
}
/**
* Called by a Worker object to
* indicate that it has completed a
* workload.
*/
synchronized public void workerEnd()
{
_activeThreads--;
notify();
}
/**
* Called to reset this object to
* its initial state.
*/
synchronized public void reset()
{
_activeThreads = 0;
}
}
Please help. Thanks in advance. Looking for your kind response.
Now I understand that whole code very perfectly. If you find any doubts in this code, then you can ask.
Answers of my questions are as follows after reading a lot on this.
Yes, you are right, it is logically wrong. Its better, if it would be _activeTasks . It is used to kill all the threads , when threadpool have no more work because waitDone() function executes successfully only when _activeTasks <= 0.
This Variable is used in waitBegin() method. Whenever any tasks starts, it updates _started by TRUE, means the tasks that are assigned by users is now in processing by threads, means threads starts working on these tasks. If tasks is not given by user, then all threads are still active , and waiting for tasks. This is the use of this variable here.
waitBegin() method executes successfully when threads starts working on tasks, because in that case only _started become true. Otherwise, threads keep on waiting for some tasks. waitDone() executes successfully only when _activeTasks become Zero, because this is the only situation when threadpool don't have any work to perform, means threadpool completes its work. Otherwise, it keep waiting until all tasks finish, means it waits until when _activeTasks becomes ZERO
I have a test case that provides arguments and executes the main method of a class. What would be the best approach using Junit to have multiple threads concurrenlty execute the main method of class.
Not sure if TestNG is an option for you, but it's pretty straightforward with it:
#Test(invocationCount = 100, threadPoolSize = 10)
public void myTest() { ... }
This will cause the test method to be invoked 100 times from 10 different threads. If this test passes and you run it a lot, you can be fairly confident that the code under test is multithread safe.
Why would you do that? Is your public static void main(String []) really run by multiple threads? Seems a strange design, that's why I'm making sure.
If, on the other hand, you want to test parallel executions of your program (so each in a separate JVM), it's not the same as multithreaded, and JUnit won't do that, as it executes within the same JVM. You still can do that, no problem, but make sure you know the difference.
Some examples on SO:
Concurrent JUnit testing
How do I test a concurrent Java program which expects cmd line arguments? (some other tools for parallel test execution in separate JVMs)
Here is a lightweight solution:
Here is the Class you want to testing:
package mTTest;
/**
* UUT class is the Unit Under Test. This will be tested.
* It has two simple method:
* push(): sets the message string if it's null, and waits otherwise.
* pop(): if there is any message sets it null and returns it.
*
*/
public class UUT {
String message = null;
synchronized void push(String msg){
while (null != message) {
try {
wait();
} catch (InterruptedException e) {
}
}
message = msg;
notifyAll();
}
synchronized String pop(){
while (null == message) {
try {
wait();
} catch (InterruptedException e) {
}
}
String ret = message;
message = null;
notifyAll();
return ret;
}
}
Here is the Test class. This will be invoked bz the JUnit framework. Rewrite multiTest() method.
package mTTest;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import org.junit.Test;
/**
* This is the JUnit test class. Method in this class will invoked by the JUnit
* framework.
*/
public class DUTTest {
/**
* Stores sub test threads errors.
*/
private static List<AssertionError> errors;
/**
* sub test threads call this function with they errors.
* #param err
*/
static void handle(AssertionError err){
errors.add(err);
}
/**
* Simpler single thread test
* #throws InterruptedException
*/
#Test
public void testSingle() {
UUT dut = new UUT();
dut.push("hello");
assertEquals("set-get", "hello", dut.message);
}
/**
* Complex multi-thread test
* #throws InterruptedException
*/
#Test
public void testMulti() throws Exception {
/*
* Initialization
*/
errors = Collections.synchronizedList(new ArrayList<AssertionError>());
UUT dut = new UUT();
MyTestThread th = new MyTestThread(dut);
/*
* Tests
*/
dut.push("hello");
assertEquals("set-get", "hello", dut.message);
th.start();
dut.push("hello");
th.join();
/*
* Error handling
*/
ListIterator<AssertionError> iter = errors.listIterator(errors.size());
while (iter.hasPrevious()) {
AssertionError err = iter.previous();
err.printStackTrace();
if(iter.previousIndex() == -1){
throw err;
}
}
}
}
Here is the Thread, which can be invoked several time. Override test() method.
package mTTest;
import static org.junit.Assert.assertEquals;
/**
* This is the custom test thread class. The main test thread (which is started
* by JUnit) starts this thread.
*
*/
public class MyTestThread extends Thread {
UUT dut;
/**
* Constructor
* #param dut : should be overwritten to your custom DUT-class
*/
public MyTestThread(UUT dut) {
this.dut =dut;
}
/**
* run() method is final to prevent overriding. Override test instead.
* It just calls the test method and handle the assertion errors.
*/
#Override
public final void run() {
try{
test();
} catch (AssertionError ex){
DUTTest.handle(ex);
}
}
/**
* Write your tests here. run calls this function.
*/
void test(){
assertEquals("set-get", "This will cause an ERROR", dut.pop());
assertEquals("set-get", "hello", dut.pop());
}
}
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.