I'm using a few services inheriting from the AbstractScheduledService, which get managed by a ServiceManager. Everything works fine, but now, there's a service whose runOneIteration takes a rather long time, and as the result, my process takes too long to terminate (more than five seconds).
There are other services inheriting from AbstractExecutionThreadService, which had a similar problem, which I could solve via
#Override
protected final void triggerShutdown() {
if (thread != null) thread.interrupt();
}
and storing private volatile thread in the run method. However, there's no triggerShutdown for AbstractScheduledService as stated in this issue.
I already considered alternatives like making runOneIteration do less work, but it's both ugly and inefficient.
I can't override stopAsync as it's final and I can't see anything else. Is there a hook for doing something like this?
Can you work with this? Was there any reason you couldn't add a triggerShutdown yourself?
class GuavaServer {
public static void main(String[] args) throws InterruptedException {
GuavaServer gs = new GuavaServer();
Set<ForceStoppableScheduledService> services = new HashSet<>();
ForceStoppableScheduledService ts = gs.new ForceStoppableScheduledService();
services.add(ts);
ServiceManager manager = new ServiceManager(services);
manager.addListener(new Listener() {
public void stopped() {
System.out.println("Stopped");
}
public void healthy() {
System.out.println("Health");
}
public void failure(Service service) {
System.out.println("Failure");
System.exit(1);
}
}, MoreExecutors.directExecutor());
manager.startAsync(); // start all the services asynchronously
Thread.sleep(3000);
manager.stopAsync();
//maybe make a manager.StopNOW()?
for (ForceStoppableScheduledService service : services) {
service.triggerShutdown();
}
}
public class ForceStoppableScheduledService extends AbstractScheduledService {
Thread thread;
#Override
protected void runOneIteration() throws Exception {
thread = Thread.currentThread();
try {
System.out.println("Working");
Thread.sleep(10000);
} catch (InterruptedException e) {// can your long process throw InterruptedException?
System.out.println("Thread was interrupted, Failed to complete operation");
} finally {
thread = null;
}
System.out.println("Done");
}
#Override
protected Scheduler scheduler() {
return Scheduler.newFixedRateSchedule(0, 1, TimeUnit.SECONDS);
}
protected void triggerShutdown() {
if (thread != null) thread.interrupt();
}
}
}
Related
I have been wanting for a long time to add schedulers to my API. So I set a class for the purpose. Here it is.
public abstract class SyncScheduler extends Scheduler {
private Thread thread = null;
private boolean repeating = false;
#Override
public synchronized void runTask() {
thread = new Thread(this);
thread.start();
}
#Override
public synchronized void runTaskLater(long delay) {
thread = new Thread(this);
try {
Thread.sleep(delay * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.run();
}
#Override
public synchronized void runRepeatingTask(long period) {
thread = new Thread(this);
repeating = true;
while (!thread.isInterrupted()) {
thread.run();
try {
Thread.sleep(period * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public synchronized void cancel() {
if (thread != null || !repeating) {
throw new SchedulerException("Scheduler is not started or is not a repeating task!");
} else {
thread.interrupt();
repeating = false;
}
}}
Scheduler just implements Runnable.
The problem is that whenever I try to create 2 or more Schedulers, the second one never starts until the first one is finished! For example if I have on Scheduler that runs every X seconds and I have another one the cancels it, the one that cancels the first one never starts! This is the problem.
How could I run two of these schedulers in parallel?
Also these are my two test main classes.
public class Test {
static Scheduler scheduler = new SyncScheduler() {
#Override
public void run() {
System.out.println("It works.");
}
};
public static void main(String[] args) {
scheduler.runRepeatingTask(1);
new SyncScheduler() {
#Override
public void run() {
System.out.println("Stopped.");
scheduler.cancel();
}
}.runTaskLater(2);
}}
And here's the second one.
public class Test {
static Scheduler scheduler = new SyncScheduler() {
#Override
public void run() {
System.out.println("It works.");
new SyncScheduler() {
#Override
public void run() {
System.out.println("Stopped.");
scheduler.cancel();
}
}.runTaskLater(2);
}
};
public static void main(String[] args) {
scheduler.runRepeatingTask(1);
}}
The first one outputs "It works." repeatedly until I force stop the test.
The second one gives me "It works." for once, then It gives me "Stopped." and with it and exception.
You are using the thread object wrongly.
To start a Runnable object (in this case, Thread object) in a different thread, the object must call start() method. You are using run() method, which just calling the method in the same thread without creating a new thread.
Try to change run() in SyncScheduler.runRepeatingTask and SyncScheduler.runTaskLater.
Also, I just noticed in your cancel() method:
if (thread != null || !repeating) {
throw new SchedulerException("Scheduler is not started or is not a repeating task!");
} else {
thread.interrupt();
repeating = false;
}
This would make the method throw exception if thread started. I think it should be if (thread == null || !repeating) {
I have a pool of worker threads (an ExecutorService).
This pool is used to run shell commands.
I use a shell (/bin/sh) rather than creating a process for the executable directly, because I use shell redirects (>) to write the output directly to disk, without having to pass through the JVM, as well as some other niceties.
Spawning a shell process takes 2-3 milliseconds.
I want each thread to keep a shell process to avoid the overhead of starting it.
How do I allow each thread to own a process?
I am thinking of using a ThreadFactory with thread locals.
class ThreadFactory {
Thread newThread(Runnable r) {
return new Thread(new Runnable() {
Process process = Runtime.getRuntime().exec("/bin/sh")
try {
// store process as thread local here
r.run(); // then r can access thread local
} catch(Exception e) {
try {
process.close();
} catch(Exception e) {
}
throw e;
}
});
}
}
(Alternatively, I could subclass Thread and cast Thread.currentThread() to that class in my Runnable.)
Is this a good approach to solving this problem?
I would keep the Process reference in a ProcessRunnable that continuously executes commands. I think is more clear than using a ThreadLocal and a ThreadFactory. Something like this:
public class ShellCommandExecutor {
private int concurrency = 10;
private int capacity = 100;
private ExecutorService service = Executors.newFixedThreadPool(concurrency);
private BlockingQueue<String> commandsQueue = new LinkedBlockingQueue<>(capacity);
public void start() {
for (int i = 0; i < concurrency; i++)
service.submit(new Runnable() {
#Override
public void run() {
//todo deal with ioexception
Process process = Runtime.getRuntime().exec("/bin/sh");
while (!Thread.currentThread().isInterrupted()) {
try {
String command = commandsQueue.take();
//todo execute commands using the same process per thread
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
});
}
public void executeCommand(String command) throws InterruptedException {
commandsQueue.put(command);
}
public void shutdown() {
service.shutdownNow();
}
}
EDIT: a solution with thread local that should work easily with cached thread pools:
public class ShellCommandExecutor2 {
//todo limit queue
private ExecutorService service = Executors.newCachedThreadPool();
public void executeCommand(final String command) throws InterruptedException {
service.submit(new Runnable() {
#Override
public void run() {
Process process = ThreadLocalProcessFactory.get();
//todo execute command
}
});
}
public void shutdown() {
service.shutdownNow();
}
private static class ThreadLocalProcessFactory {
private static final ThreadLocal<Process> processThreadLocal =
new ThreadLocal<Process>() {
#Override protected Process initialValue() {
try {
return Runtime.getRuntime().exec("/bin/sh");
}
catch (IOException e) {
e.printStackTrace();
return null;
}
}
};
static Process get() {
return processThreadLocal.get();
}
}
}
I try to run junit from my main() method:
public static void main(String... args) throws ClassNotFoundException,
IOException {
//...
logger.debug("className " + className + "methodName " + methodName);
Request request = Request.method(Class.forName(className), methodName);
return new JUnitCore().run(request);
}
I have an E2E test with 10 commands (say). It is run by JUnit and I want to limit the run time of commands 3-5 to X millis (where X is determined at run time). If it runs longer than X I want to return to the main() and print something.
I have tried System.exit() but it closes the whole application. I tried:
public void setTimeOut(String criticalBlockTimeOutMilli) {
if (criticalBlockTimeOutMilli != null) {
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
E2eResult e2eResult = E2eResult.getInstance();
e2eResult.status = E2eStatus.TIMEOUT;
//System.exit(2);
}
};
new Timer().schedule(timerTask, Long.parseLong(criticalBlockTimeOutMilli));
}
}
public void setTimeOut(final Thread thread, String criticalBlockTimeOutMilli) {
if (criticalBlockTimeOutMilli != null) {
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
E2eResult e2eResult = E2eResult.getInstance();
e2eResult.status = E2eStatus.TIMEOUT;
thread.interrupt();
}
};
new Timer().schedule(timerTask, Long.parseLong(criticalBlockTimeOutMilli));
}
}
but the main thread continues to run the test even if exceeds the limit. What would you suggest?
Unit testing might not be the best approach to solving this sort of performance testing. However, if there's some reason this must be done, read on...
Use an ExecutorService to run the commands you want, with a given timeout. If the timeout expires, throw your own exception that you can catch in your main thread:
#Test
public void yourTest() throws Exception {
// Do commands 1-2
ExecutorService service = Executors.newSingleThreadExecutor();
Future<Void> result = service.submit(new Callable<Void>() {
#Override
public Void call() throws Exception {
// call commands 3-5
return null;
}
});
try {
result.get(42, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
throw new YourOwnException();
}
service.shutdown();
// Do commands 6-10
}
One fairly simple mechanism is to use a BlockingQueue to indicate that the test completed. If you find it didn't you can then interrupt it. This will only work if the test correctly responds to being interrupted.
// Send FINISHED down this queue when test completes.
final BlockingQueue<Object> finished = new ArrayBlockingQueue<>(1);
// FINISHED cookie.
static final Object FINISHED = new Object();
public void test() throws InterruptedException {
Thread test = new Thread(new Runnable() {
#Override
public void run() {
// Do your stuff.
// ...
// Signal we finished.
finished.add(FINISHED);
}
});
// Start the test in it's own thread.
test.start();
try {
// Wait for your time.
if (FINISHED == finished.poll(5, TimeUnit.MILLISECONDS)) {
// It completed! No problems.
} else {
// It hasn't finished! Interrupt it.
test.interrupt();
};
} catch (InterruptedException ex) {
// We were interrupted! Do something.
test.interrupt();
// Rethrow it.
throw(ex);
}
}
You can extend this mechanism by adding a "Started" message too so you can ensure that the test thread gets at least a chance to run.
I have the following code:
public class Shell {
String status;
Runtime rtime;
Process process;
public void runCmd(final String cmd,String status) throws Exception{
this.status = status;
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
process = rtime.exec(cmd);
process.waitFor();
this.status = "check out done";
} catch (IOException e) {
} catch (InterruptedException e) {
}
}
});
t.start();
}
}
but java doesn't let me change the status variable inside the new thread t.May be I need some sort of inter thread communication.I am new to threads,please tell me how to do this.
In your case this in expression this.status refers Runnable object which does not have status field defined. Try Shell.this.status instead of this.status.
The problem is that you cannot access a variable from a parent class in an anonymous class unless it is final and even then it is complex. As you want to modify it I would suggest something like:
public class Holder <T> {
private T held = null;
public Holder () {
}
public Holder (T it) {
held = it;
}
public void hold(T it) {
held = it;
}
public T held() {
return held;
}
#Override
public String toString () {
return held == null ? "null": held.toString();
}
}
Then your code can look like this:
public class Shell {
final Holder<String> status = new Holder<>();
Runtime rtime;
Process process;
public void runCmd(final String cmd, String status) throws Exception {
// Set the status.
Shell.this.status.hold(status);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
process = rtime.exec(cmd);
process.waitFor();
Shell.this.status.hold("check out done");
} catch ( IOException | InterruptedException e) {
}
}
});
t.start();
}
}
Added
This demopnstration of the use of a Holder is the solution to a different problem - i.e. the need to modify a final object from inside an anonymous class.
This answer is not the solution to OP's problem and I would delete it if I could. Unfortunately it has been marked as the answer so I cannot.
If OP could mark one of the other posts as the correct answer I would be happy to delete this.
public class Shell {
volatile String status;
public void runCmd(final String cmd) throws Exception{
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
Process process = Runtime.getRuntime().exec(cmd);
process.waitFor();
Shell.this.status = "check out done";
} catch (IOException e) {
} catch (InterruptedException e) {
}
}
});
t.start();
t.join();
System.out.println(status);
}
}
Use Shell.this.status and update the value to what to want.
Thread Safety
Always use volatile when reference is updated from another thread.
Essentially, what I want to do is start all my threads, pause them all, then resume them all, using the multithreading approach. I am just looking for a simple solution to this. I'm not sure if I have to use a timer or what. Right now when I run it, the threads are like being executed in random order (I guess the PC is just randomly picking which ones it wants to run at a certain time).
class ChoppingThread extends Thread
{
public void run()
{
for(int j=40;j!=0;j-=10)
System.out.println("Chopping vegetables...("+j+" seconds left)");
}
}
class MixingThread extends Thread
{
public void run()
{
for(int k=60;k!=0;k-=10)
System.out.println("Mixing sauces...("+k+" seconds left)");
}
}
class TenderizingThread extends Thread
{
public void run()
{
for(int j=50;j!=0;j-=10)
System.out.println("Tenderizing meat...("+j+" seconds left)");
}
}
class MultiThreadTasking
{
public static void main (String [] args)
{
ChoppingThread ct = new ChoppingThread();
MixingThread mt = new MixingThread();
TenderizingThread tt = new TenderizingThread();
System.out.println("\nWelcome to the busy kitchen.");
//putting threads into ready state
ct.start();
mt.start();
tt.start();
}
}
There are probably other ways to achieve the same result, but this is the simplest I can come up with off the top of my head (I know, sad isn't it)...
Basically, this is a special Runnable with some additional management functionality.
This basically contains a state flag that indicates the state of the task and a monitor lock
public class ThreadFun {
public static void main(String[] args) {
MyTask task = new MyTask();
Thread thread = new Thread(task);
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
task.pauseTask();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
task.resumeTask();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
task.stopTask();
}
public enum TaskState {
Running,
Stopped,
Paused
}
public static class MyTask implements Runnable {
private static final Object PAUSED_LOCK = new Object();
private volatile TaskState state = TaskState.Running;
public void pauseTask() {
if (state == TaskState.Running) {
System.out.println("Paused...");
state = TaskState.Paused;
}
}
public void resumeTask() {
if (state == TaskState.Paused) {
state = TaskState.Running;
synchronized (PAUSED_LOCK) {
PAUSED_LOCK.notifyAll();
}
System.out.println("Resumed...");
}
}
public void stopTask() {
if (state == TaskState.Running || state == TaskState.Paused) {
state = TaskState.Stopped;
System.out.println("Stopped...");
}
}
public boolean isStopped() {
return state == TaskState.Stopped;
}
public boolean isPaused() {
return state == TaskState.Paused;
}
protected void doPause() {
synchronized (PAUSED_LOCK) {
while (isPaused()) {
try {
PAUSED_LOCK.wait();
} catch (InterruptedException ex) {
}
}
}
}
#Override
public void run() {
int index = 0;
while (!isStopped() && index < 1000) {
try {
Thread.sleep(25);
} catch (InterruptedException ex) {
}
doPause();
index++;
System.out.println(index);
}
stopTask(); // Make sure the task is marked as begin stopped ;)
}
}
}
The main criteria is you will need to pool isStopped and doPause at appropriate points to ensure that they are begin implemented as required...
To coordinate them use a CyclicBarrier.
To launch them all at the same time use a CountDownLatch.
Google the two classes above for many examples and explanations.
To fully understand what is happening read the Java Concurrency In Practice book.
I believe you can accomplish this by using Object.wait and Thread.interrupt.
Object.wait blocks until notify is called. So
private boolean paused;
private Object waitObject;
...
public void run() {
for ... {
if (this.paused) { this.waitObject.wait(); }
...
public void pause() { this.paused = true; }
public void resume() { this.paused = false; this.waitObject.notify(); }
Then you can call pause to pause the thread.
Thread.interrupt can help with stopping.
private boolean paused;
...
public void run() {
for ... {
// interrupted() is different from interrupt()!
if (this.iterrupted()) { break; }
...
To stop it, you would call interrupt() from another thread.
This is the basic idea, but there's a lot of details to worry about here. For example, wait can throw an InterruptedException you'll need to handle. Also, wait is not guaranteed to return only after a notify. It can return randomly. Here is a pair of tutorials:
Wait: http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
Interrupt: http://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html