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 {
//
}
}
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 ...
I had a look at JAVA and tried to play around with an ExecutorService. Unfortunately my executor doesn’t start my runnable objects.
I’m trying to get some information from different XML files, which are stored in the files list.
FileFinder fileFinder = new FileFinder(path);
List<File>files = fileFinder.getFiles();
ExecutorService threadPool = Executors.newFixedThreadPool(configReader.getThreadcount(), new ThreadFactory() {
#Override
public Thread newThread(Runnable r) {
return new EinbucherThread();
}
});
for(File file : files)
{
System.out.println("Started working");
USEinbucher einbucher = new USEinbucher(file, verbindung);
threadPool.execute(einbucher);
}
threadPool.shutdown();
try {
while(!threadPool.awaitTermination(1, TimeUnit.SECONDS)) {
i++;
System.out.println("waiting "+i );
;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
I thought I could increase the performance by putting the unmarshaller in my threads. So I don’t need to create an unmarshaller for each file, but just once per thread (as far as I understood the API each thread can be used multiple times).
public class EinbucherThread extends Thread {
private Unmarshaller um;
public EinbucherThread() {
try {
JAXBContext jb = JAXBContext.newInstance("klassen");
um = jb.createUnmarshaller();
System.out.println("Thread was created");
} catch (JAXBException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Unmarshaller getUm() {
return um;
}
Unfortunately it seems, as if the run method of my runnable class is never reached.
public class USEinbucher implements Runnable {
private File lieferung;
private Verbindung verbindung;
public USEinbucher(File lieferung, Verbindung verbindung) {
this.lieferung=lieferung;
this.verbindung=verbindung;
}
#Override
public void run()
{
System.out.println("Started to work");
einbuchen();
}
I inserted some println for debugging. With three files and a threadcount of two my output looks like:
Started working
Thread was created
Started working
Thread was created
Started working
Thread was created
waiting 1
waiting 2
waiting 3…
Any explanation is appreciated.
The ThreadFactory.newThread should return a Thread that is responsible for running the parameter Runnable object. Consider passing the Runnable parameter to your Thread object. For example:
#Override
public Thread newThread(Runnable r) {
return new EinbucherThread(r);
}
//in the constructor of EinbucherThread
public EinbucherThread (Runnable r){
super(r);
}
I am currently trying to get my code to print what is in the method of simpleTask 20 times using the code in simpleTesting. The idea is that simpleTesting adds 20 instances of simpleTask to a queue then they are taken from the queue in simplePoolThread. What should happen is that it prints out the testing message 20 times then continues to run while looking for more things from the queue (but there are none). Instead it is currently just not printing anything and continuously running. Here is my code (a lot of it is interfaces, I believe the problem lies in the simpleThreadPool code):
package simpleThreadPool;
/**
* <<-- Pool Thread -->>
*
* It will be running continuously. It will try to retrieve new tasks when it is idle.
*/
public interface ISimplePoolThread extends Runnable {
/**
* Use an infinite loop to retrieve and perform tasks.
*/
#Override
public void run();
}
.
package simpleThreadPool;
/**
* <<-- Simple Task -->>
*
* ISimpleTask is to be performed by PoolThread.
*/
public interface ISimpleTask{
/**
* #1. Create a class to implement ISimpleTask, put content of the task to method run().
*/
public void run();
}
.
package simpleThreadPool;
/**
* <<-- Thread Pool -->>
* It manages a queue of tasks, starts some pool threads.
*
* #1. Create a task queue by using queue data structures, or designing your own data structure.
*/
public interface ISimpleThreadPool {
/**
* #1. Initialize your queue (or do so in somewhere)
* #2. Starts some ISimplePoolThreads.
*/
public void start();
/**
* #1. Stops everything
*/
public void stop();
/**
* #1. Add a task to your queue.
*/
public void addTask(ISimpleTask task);
}
.
package simpleThreadPool;
public class SimpleTask implements ISimpleTask {
#Override
public void run() {
System.out.println("testing testing 1 2 3");
}
}
.
I think the problem lies in this piece of code, where the tasks are taken from the queue:
package simpleThreadPool;
import java.util.concurrent.LinkedBlockingQueue;
public class SimplePoolThread implements ISimplePoolThread, Runnable {
private LinkedBlockingQueue<ISimpleTask> queue = new LinkedBlockingQueue<>();
#Override
public void run() {
while(true) {
System.out.println("Inserting Element: ");
try {
queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
.
package simpleThreadPool;
import java.util.concurrent.LinkedBlockingQueue;
public class SimpleThreadPool implements ISimpleThreadPool {
private LinkedBlockingQueue<ISimpleTask> queue = new LinkedBlockingQueue<>();
#Override
public void start() {
(new Thread(new SimplePoolThread())).start();
}
#Override
public void stop() {
try {
queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void addTask(ISimpleTask task) {
try {
queue.put(task);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
.
the testing file:
package simpleThreadPool;
public class SimpleTesting implements ISimpleTask{
private int i;
public SimpleTesting(int i){
this.i = i;
}
#Override
public void run() {
System.out.println(i);
}
public static void main(String args[]){
// Initialize thread pool
SimpleThreadPool pool = new SimpleThreadPool();
pool.start();
// Create 20 tasks
for(int i = 1; i<=20; i++){
pool.addTask(new SimpleTesting(i));
}
}
}
The task queue in your SimplePoolThread is a blocking queue. As soon as it starts it executes queue.take(). Take is a blocking operation. The thread sits there waiting forever until something else adds a task into the queue.
Your hunch on the problem location was pretty close. The issue is that the queue in SimplePoolThread and the queue in SimpleThreadPool are not the same; you have two separate queues. So when SimpleTesting adds tasks they go into Pool's queue and NOT into the Thread's queue. So the thread will sit there forever waiting on nothing. You also forgot to actually run your tasks inside of SimplePoolThread.
Try the following instead.
public class SimpleThreadPool implements ISimpleThreadPool {
private LinkedBlockingQueue<ISimpleTask> queue = new LinkedBlockingQueue<>();
#Override
public void start() {
(new Thread(new SimplePoolThread(queue))).start();
}
Note that the queue from the pool was passed into the thread. The thread then keeps a reference to this queue. During the thread's run() it now also actually runs the task.
public class SimplePoolThread implements ISimplePoolThread, Runnable {
private LinkedBlockingQueue<ISimpleTask> queue;
public SimplePoolThread(LinkedBlockingQueue<ISimpleTask> queue)
{
this.queue = queue;
}
#Override
public void run() {
while(true) {
System.out.println("Inserting Element: ");
try {
ISimpleTask task = queue.take();
task.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Here's the output:
Inserting Element:
1
Inserting Element:
2
Inserting Element:
3
..etc..
I assume this is for homework otherwise I would tell you not to reinvent the wheel and go use Java's built-in pooling services.
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html
I am trying to develop a project for my graduation project. I am using free version of Hazelcast so i couldn't ask support for help.
I wrote a java application that works on single computer. I am using LinkedList for queue, and have a pool of 5 worker threads. Worker threads just take one of the job from queue and executes it.
Code for the job:
package com.stackoverflow.multithread.app;
import java.util.Date;
/**
* Job
*/
public class Job implements Runnable {
private final Object req;
private final long createTime = new Date().getTime();
public Job(Object req) {
this.req = req;
}
public boolean isPoison() {
return req == null;
}
public long getWaitTime(){
return new Date().getTime() - createTime;
}
#Override
public void run() {
try {
//Do the job
} catch (Exception e){
e.printStackTrace();
}
}
}
Code for the Work Queue
package com.stackoverflow.multithread.app;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* WorkQueue
*/
public class WorkQueue {
private static int minThreads;
private static int maxThreads;
private static final List<PoolWorker> threads = new ArrayList<PoolWorker>();
private static final LinkedList queue = new LinkedList();
private static WorkQueue instance = null;
/**
* WorkQueue
*/
protected WorkQueue() {
minThreads = 1;
maxThreads = 5;
for (int i = 0; i < minThreads; i++) {
PoolWorker worker = new PoolWorker();
threads.add(worker);
worker.start();
}
}
/**
* getInstance
*
* #return Singleton WorkQueue instance
*/
public static WorkQueue getInstance() {
if (instance == null) {
instance = new WorkQueue();
}
return instance;
}
/**
* clone
*
* #return null
* #throws CloneNotSupportedException: Singleton class can not be cloned.
*/
#Override
public WorkQueue clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("Singleton class can not be cloned.");
}
public void execute(Job r) {
synchronized (queue) {
queue.addLast(r);
manageWorkers();
queue.notify();
}
}
private void manageWorkers(){
while ((queue.size() / 2 > threads.size() || (queue.size() > 0 && ((Job)queue.peekFirst()).getWaitTime() > 1000)) && threads.size() < maxThreads){
PoolWorker worker = new PoolWorker();
threads.add(worker);
worker.start();
}
if (queue.size() < threads.size() && threads.size() > minThreads){
execute(new Job(null)); //poison
}
}
private class PoolWorker extends Thread {
#Override
public void run() {
Job r;
while (true) {
synchronized (queue) {
while (queue.isEmpty()) {
try {
queue.wait();
} catch (InterruptedException ignored) {
}
}
r = (Job) queue.removeFirst();
manageWorkers();
if (r.isPoison()) {
break;
}
}
// If we don't catch RuntimeException,
// the pool could leak threads
try {
r.run();
} catch (RuntimeException e) {
e.printStackTrace();
} catch (ExceptionInInitializerError e){
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
}
threads.remove(this);
}
}
}
Now i want to make this work on an active-active cluster and want to use HazelCast (v3.3), to ensure that each and all the jobs should be executed exactly once, even if one of the computers is down.
I checked ExecutorService yet it executes the jobs one by one (single thread). I couldn't find a good solution to do this. People mention ParallelExecutorService yet it is either not usable in this version, or it is not part of free edition.
Please note that I don't have to do this using Hazelcast. Any free solution is fine by me.
Any suggestions?
Why don't you make use of the IExecutorService, which implements the Executor(Service) interface. So you can just throw a task in there (make sure it is serializable) and any member in the cluster can take that task to process it.
No need to mess around with your own threadpools.
Here are set of examples you can have a look at:
https://github.com/hazelcast/hazelcast-code-samples/tree/master/distributed-executor
I have a bunch of threads running concurrently. Sometimes a thread needs to notify other threads to wait for it to finish a job and signal them again to resume. Since I'm somehow new to Java's synchronization, I wonder what is the right way to do such thing. My code is something like this:
private void Concurrent() {
if (shouldRun()) {
// notify threads to pause and wait for them
DoJob();
// resume threads
}
// Normal job...
}
Update:
Note that the code I wrote is inside a class which will be executed by each thread. I don't have access to those threads or how they are running. I'm just inside threads.
Update 2:
My code is from a crawler class. The crawler class (crawler4j) knows how to handle concurrency. The only thing I need is to pause other crawlers before running a function and resume them afterwards. This code is the basics of my crawler:
public class TestCrawler extends WebCrawler {
private SingleThread()
{
//When this function is running, no other crawler should do anything
}
#Override
public void visit(Page page) {
if(SomeCriteria())
{
//make all other crawlers stop until I finish
SingleThread();
//let them resume
}
//Normal Stuff
}
}
Here is a short example on how to achieve this with the cool java concurrency stuff:
snip old code doesn't matter anymore with the Pause class.
EDIT:
Here is the new Test class:
package de.hotware.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
private Pause mPause;
public Test() {
this.mPause = new Pause();
}
public void concurrent() throws InterruptedException {
while(true) {
this.mPause.probe();
System.out.println("concurrent");
Thread.sleep(100);
}
}
public void crucial() throws InterruptedException {
int i = 0;
while (true) {
if (i++ % 2 == 0) {
this.mPause.pause(true);
System.out.println("crucial: exclusive execution");
this.mPause.pause(false);
} else {
System.out.println("crucial: normal execution");
Thread.sleep(1000);
}
}
}
public static void main(String[] args) {
final Test test = new Test();
Runnable run = new Runnable() {
#Override
public void run() {
try {
test.concurrent();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
Runnable cruc = new Runnable() {
#Override
public void run() {
try {
test.crucial();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
ExecutorService serv = Executors.newCachedThreadPool();
serv.execute(run);
serv.execute(run);
serv.execute(cruc);
}
}
And the utility Pause class:
package de.hotware.test;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Utility class to pause and unpause threads
* with Java Concurrency
* #author Martin Braun
*/
public class Pause {
private Lock mLock;
private Condition mCondition;
private AtomicBoolean mAwait;
public Pause() {
this.mLock = new ReentrantLock();
this.mCondition = this.mLock.newCondition();
this.mAwait = new AtomicBoolean(false);
}
/**
* waits until the threads until this.mAwait is set to true
* #throws InterruptedException
*/
public void probe() throws InterruptedException {
while(this.mAwait.get()) {
this.mLock.lock();
try {
this.mCondition.await();
} finally {
this.mLock.unlock();
}
}
}
/**
* pauses or unpauses
*/
public void pause(boolean pValue) {
if(!pValue){
this.mLock.lock();
try {
this.mCondition.signalAll();
} finally {
this.mLock.unlock();
}
}
this.mAwait.set(pValue);
}
}
The basic usage is to call probe() before each run. This will block if it is paused until pause(false) is called.
Your class would look like this:
public class TestCrawler extends WebCrawler {
private Pause mPause;
public TestCrawler(Pause pPause) {
this.mPause = pPause;
}
private SingleThread()
{
//When this function is running, no other crawler should do anything
}
#Override
public void visit(Page page) {
if(SomeCriteria())
{
//only enter the crucial part once if it has to be exclusive
this.mPause.probe();
//make all other crawlers stop until I finish
this.mPause.pause(true);
SingleThread();
//let them resume
this.mPause.pause(false);
}
this.mPause.probe();
//Normal Stuff
}
}
public class StockMonitor extends Thread {
private boolean suspend = false;
private volatile Thread thread;
public StockMonitor() {
thread = this;
}
// Use name with underscore, in order to avoid naming crashing with
// Thread's.
private synchronized void _wait() throws InterruptedException {
while (suspend) {
wait();
}
}
// Use name with underscore, in order to avoid naming crashing with
// Thread's.
public synchronized void _resume() {
suspend = false;
notify();
}
// Use name with underscore, in order to avoid naming crashing with
// Thread's.
public synchronized void _suspend() {
suspend = true;
}
public void _stop() {
thread = null;
// Wake up from sleep.
interrupt();
}
#Override
public void run() {
final Thread thisThread = Thread.currentThread();
while (thisThread == thread) {
_wait();
// Do whatever you want right here.
}
}
}
Calling _resume and _suspend will enable you to resume and pause the Thread. _stop will let you stop the thread gracefully. Note that, once you stop the Thread, there is no way to resume it again. The Thread is no longer usable.
The code is being picked from a real world open source project : http://jstock.hg.sourceforge.net/hgweb/jstock/jstock/file/b17c0fbfe37c/src/org/yccheok/jstock/engine/RealTimeStockMonitor.java#l247
You can use wait() and notify()
thread waiting:
// define mutex as field
Object mutex = new Object();
// later:
synchronized(mutex) {
wait();
}
notify the thread to continue
synchronized (mutex) {
notify();
}