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());
}
}
Related
I learned that in JavaFX the equivalent of
SwingUtilities.invokeLater(new Runnable() {
public void run() {
dosomething();
}
});
might simply be
Platform.runLater(() ->{ dosomething()};
for a long running task I learned that you need to wrap things with a Task like:
Task<Void> task = new Task<Void>() {
#Override
public Void call() {
dosomething();
}
};
new Thread(task).start();
Now it would be great to be able to have a similar lambda shortcut like
TaskLaunch.start(() -> dosomething());
I found
JAVA FX - Lambda for Task interface
Swing timer alternative for JavaFX and the thread management difference
Thread with Lambda expression
discussing some of the issues around this and tried:
package com.bitplan.task.util;
import java.util.concurrent.Callable;
import javafx.concurrent.Task;
/**
* this is a utility task to launch tasks with lambda expressions
*
* #author wf
*
*/
public class TaskLaunch {
/**
*
* #param callable
* #return the new task
*/
public static <T> Task<T> task(Callable<T> callable) {
Task<T> task = new Task<T>() {
#Override
public T call() throws Exception {
return callable.call();
}
};
return task;
}
}
with a JUnit test:
Integer counter=0;
boolean running=false;
public Integer increment() {
running=true;
while (running) {
counter++;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
}
return counter;
}
/**
* #throws Exception
*/
#Test
public void testTaskLaunch() throws Exception {
// https://stackoverflow.com/questions/30089593/java-fx-lambda-for-task-interface
Task<Integer> task=TaskLaunch.task(() -> increment());
try {
Thread.sleep(20);
} catch (InterruptedException e) {
//
}
running=false;
assertTrue(task.get()>10);
}
Which doesn't quite do what I'd like to see yet. The issue seems to be that
the lambda expression runs in the same Thread and the
new Thread(task).start();
part needs to be integrated.
What is needed to get (at least close to) the short one liner mentioned above?
Is a
TaskLaunch.start(() -> dosomething());
feasible?
based on #Damianos proposal https://stackoverflow.com/a/44817217/1497139
I tried:
package com.bitplan.task;
import java.util.concurrent.Callable;
import javafx.concurrent.Task;
/**
* this is a utility task to launch tasks with lambda expressions
*
* #author wf
*
*/
public class TaskLaunch<T> {
Thread thread;
Task<T> task;
Callable<T> callable;
Throwable throwable;
Class<T> clazz;
public Thread getThread() {
return thread;
}
public void setThread(Thread thread) {
this.thread = thread;
}
public Task<T> getTask() {
return task;
}
public void setTask(Task<T> task) {
this.task = task;
}
public Callable<T> getCallable() {
return callable;
}
public void setCallable(Callable<T> callable) {
this.callable = callable;
}
public Throwable getThrowable() {
return throwable;
}
public void setThrowable(Throwable throwable) {
this.throwable = throwable;
}
public Class<T> getClazz() {
return clazz;
}
public void setClazz(Class<T> clazz) {
this.clazz = clazz;
}
/**
* construct me from a callable
*
* #param callable
*/
public TaskLaunch(Callable<T> callable, Class<T> clazz) {
this.callable = callable;
this.task = task(callable);
this.clazz = clazz;
}
/**
*
* #param callable
* #return the new task
*/
public static <T> Task<T> task(Callable<T> callable) {
Task<T> task = new Task<T>() {
#Override
public T call() throws Exception {
return callable.call();
}
};
return task;
}
/**
* start
*/
public void start() {
thread = new Thread(task);
thread.start();
}
/**
* start the given callable
* #param callable
* #param clazz - the return Type class
* #return - the launch result
*/
#SuppressWarnings({ "unchecked", "rawtypes" })
public static TaskLaunch start(Callable<?> callable, Class<?> clazz) {
TaskLaunch<?> launch = new TaskLaunch(callable, clazz);
launch.start();
return launch;
}
}
and changed the test to:
/**
* #throws Exception
*/
#SuppressWarnings("unchecked")
#Test
public void testTaskLaunch() throws Exception {
// https://stackoverflow.com/questions/30089593/java-fx-lambda-for-task-interface
TaskLaunch<Integer> launch = TaskLaunch.start(()->increment(),Integer.class);
try {
Thread.sleep(20);
} catch (InterruptedException e) {
//
}
running=false;
assertTrue(launch.getTask().get()>10);
}
This is close to what i am up to but I get:
java.lang.IllegalStateException: Toolkit not initialized
at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273)
at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268)
at javafx.application.Platform.runLater(Platform.java:83)
at javafx.concurrent.Task.runLater(Task.java:1225)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1417)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:745)
At least TaskLaunch now wraps:
Thread
task
callable
a potential Exception/Throwable
the runtime class of the result of the Task
Some of these 5 items might be redundant and available from the standard java concepts. I think at least its handy to have quick access to these after running things from a one liner.
Hope this gets to a working state and thanks for the help!
Just new Thread(() -> dosomething()).start() should do the trick
This is sort of a traditional XY problem.
A Task is much more than just a background thread, hence for this you can use regular threads. It's the beauty of the properties!
The real benefit of using Task is that all state changes and progress updates can safely be observed and bound to a live scene, while doing all the background work on a different thread. It's the work of the class to do the heavy-lifting and call Platform.runLater.
The reason you need a subclass and not a runnable is so you can call its protected updateXxx() methods without worrying for threading issues.
With this said, you'll have no benefit if this would've been a single line code. For this use simple threads.
Hope this helps.
Doing this will cause you to lose the ability to update stuff back to the UI thread natively supported by Task class. On the other hand, I do agree this can be useful if you want to do something in background in "do-and-forget" style.
The problem is just like what you said - you didn't add new Thead() and Thread.start() in. Do this:
public static void runInBackground(Runnable runnable) {
Task<Void> task = new Task<>() {
#Override
public Void call() throws Exception {
runnable.run();
return null;
}
};
new Thead(task).start();
}
runInBackground(() -> System.out.println(Thread.currentThread().hashCode()));
Note that your Task can no longer be non-void, because it cannot return anything back now. Your lambda needs to be able to reference the Task object to return a result asynchronously - that is never going to be possible using lambda.
The answer is now in the question based on Damianos hint.
The workaround for the exception I found is
com.sun.javafx.application.PlatformImpl.startup(() -> {
});
But seems a little bit hacky ...
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.
Here I've got a thread
#Component("sessionStateListenerThread")
public class SessionStateListenerThread extends Thread {
private static final String DEFAULT_RESULT = "expired";
private List<DeferredResult<String>> subscribed = Collections
.synchronizedList(new ArrayList<DeferredResult<String>>());
/**
* Main thread loop for checking session state.
*/
#Override
public void run() {
while (true) {
synchronized (subscribed) {
try {
if (null == SecurityHelper.getUserLogin()) {
Iterator<DeferredResult<String>> it = subscribed.iterator();
while (it.hasNext()) {
DeferredResult<String> result = it.next();
result.setResult(DEFAULT_RESULT);
it.remove();
}
}
} catch (NullPointerException e) {
}
}
}
}
/**
* Adds client to listen session state.
*
* #param client
*/
public void addClient(DeferredResult<String> client) {
synchronized (subscribed) {
subscribed.add(client);
}
};
}
This class is used to wrap that thread
#Component
#DependsOn("sessionStateListenerThread")
public class SessionStateListener {
#Autowired
private SessionStateListenerThread thread;
#PostConstruct
public void configThread() {
thread.setDaemon(true);
thread.setName("SessionStateChecker");
}
/**
* Starts listener.
*/
public void startListener() {
thread.start();
}
/**
* Adds client to write result.
*
* #param client object to write result
*/
public void addSessionStateListener(DeferredResult<String> client) {
thread.addClient(client);
}
}
I put method startListener inside controller method. Also in controller I access method getUserLogin.
String login = SecurityHelper.getUserLogin(); // successfully access it
listener.startListener();
Method run in thread want to access this method getUserLogin too.
But despite login value being not null - invokation of SecurityHelper.getUserLogin() throws NullPointerException inside thread.
What's the problem? getUserLogin looks like this
return SecurityContextHolder.getContext().getAuthentication().getName();
Stacktrace is somehow small (e.printstacktrace())
java.lang.NullPointerException
at com.ui.web.security.SecurityHelper.getUserLogin(SecurityHelper.java:45)
at com.ui.web.controller.rest.poll.SessionStateListenerThread.run(SessionState
ListenerThread.java:41)
It's because you can't get current session data (context) into separate thread than current request thread.
You will be able to get any session data into any controller method, because any controller method will be executed within request thread.
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
Is there any way to find the name of the main class used to launch the current JVM, from arbitrary code running in that JVM?
By arbitrary, I mean that the code is not necessarily running in the main thread, or may be running in the main thread before main has even been called (e.g., code in a user-supplied java.system.classloader, which runs before main since it's used to load main) - so examining the call stack is not possible.
This is the closest I can get and you can take it from here.I can not guarantee that it is truly portable and it will not work if any method is invoking main method of another class.Let me know if you find more clean solution
import java.util.Map.Entry;
public class TestMain {
/**
* #param args
* #throws ClassNotFoundException
*/
public static void main(String[] args) throws ClassNotFoundException {
System.out.println(findMainClass());
}
public static String findMainClass() throws ClassNotFoundException{
for (Entry<Thread, StackTraceElement[]> entry : Thread.getAllStackTraces().entrySet()) {
Thread thread = entry.getKey();
if (thread.getThreadGroup() != null && thread.getThreadGroup().getName().equals("main")) {
for (StackTraceElement stackTraceElement : entry.getValue()) {
if (stackTraceElement.getMethodName().equals("main")) {
try {
Class<?> c = Class.forName(stackTraceElement.getClassName());
Class[] argTypes = new Class[] { String[].class };
//This will throw NoSuchMethodException in case of fake main methods
c.getDeclaredMethod("main", argTypes);
return stackTraceElement.getClassName();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
}
}
return null;
}
}