Can I get a future object from a handler?
Handler handler = new Handler(getMainLooper());
Future<String> future = handler.post(new Callable<String>() {
public String call() throw Exception {
// run in the main thread
return askForPassword();
}
}); // can I do something like this?
String password = future.get(); // wait until finish
// do network things...
I have a network thread and I need to ask the user for password, since I need to show an input dialog I have to do this on Main thread, but handler can not return values.
I can do the same thing by
Handler handler = new Handler(getMainLooper());
String password = null;
handler.post(() -> {
// run in the main thread
password = askForPassword();
});
while (password == null) { /*wait until finish*/ }
// do network things...
But this looks stupid and inconvenient
Handler is fundamentally asynchronous and thus whatever you put there is not guaranteed to run immediately (moreover, you can postDelayed or postAtTime). Then it is clear, that you can not return any value from the Handler directly to the code that posted it. So you have to work this around.
Another obstacle is that in Java your closure can capture only final variables and you have to work this around as well.
New API (CompletableFuture)
Unfortunately original Future Java API is not suitable for composition. If you target new devices only and thus can use newer CompletableFuture, you may do something like this:
CompletableFuture<String> askForPasswordNewApi() {
// your UI code that creates Future
}
void doNetworkThingNewApi() {
// some network stuff
final CompletableFuture<String> passwordFutureWrapper = new CompletableFuture<String>();
Handler handler = new Handler(getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
// run in the main thread
CompletableFuture<String> future = askForPasswordNewApi();
// bind the real future to the outer one
future.handle((r, ex) -> {
if (ex != null)
passwordFutureWrapper.completeExceptionally(ex);
else
passwordFutureWrapper.complete(r);
return 0;
});
}
});
// wait until finish
// don't forget to handle InterruptedException here
String password = passwordFutureWrapper.get();
// do more network things...
}
The idea is rather simple: create outer final variable passwordFutureWrapper that can be captured by the Handler and bind this wrapper to the real future
Side note: if your askForPassword already returns Future but you can't use the new API, you probably have re-implemented something similar to CompletableFuture anyway, so you just need to modify this code a bit to allow binding of one future to another.
Old API
If you can't use CompletableFuture in your code yet, but still somehow has a method with a Future-based signature:
Future<String> askForPasswordOldApi()
you may do it more explicitly:
void doNetworkThingOldApi() {
// some network stuff
final CountDownLatch syncLock = new CountDownLatch(1);
final Future<String>[] futureWrapper = new Future<String>[1];
Handler handler = new Handler(getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
// run in the main thread
final CompletableFuture<String> future = askForPasswordOldApi();
futureWrapper[0] = future;
syncLock.countDown();
}
});
String password;
try {
// 1 minute should be quite enough for synchronization between threads
if (!syncLock.await(1, TimeUnit.MINUTES)) {
// log error, show some user feedback and then stop further processing
return;
}
password = futureWrapper[0].get(); // wait until finish
} catch (InterruptedException ex) {
// log error, show some user feedback and then stop further processing
return;
} catch (ExecutionException ex) {
// log error, show some user feedback and then stop further processing
return;
}
// do more network things...
}
The idea here is following:
Use single-element array as a simple container to work around final-closure limitations
Use CountDownLatch to ensure synchronization between the network and the UI threads i.e. that futureWrapper[0] is not null by the time we start waiting on the result with get.
Update (design for library API)
If you are designing API and want to have a single entry for login with different additional scenarios handled by a callback, I'd do using custom implementation of something similar to CompletableFuture:
public interface ResultHandler<T> {
void resolve(T result);
void cancel();
}
class ResultHandlerImpl<T> implements ResultHandler<T> {
enum State {
Empty,
Resolved,
Cancelled
}
private final Object _lock = new Object();
private State _state = State.Empty;
private T _result;
#Override
public void resolve(T result) {
synchronized (_lock) {
if (_state != State.Empty) // don't override current state
return;
_result = result;
_state = State.Resolved;
_lock.notifyAll();
}
}
#Override
public void cancel() {
synchronized (_lock) {
if (_state != State.Empty) // don't override current state
return;
_state = State.Cancelled;
_lock.notifyAll();
}
}
public boolean isCancelled() {
synchronized (_lock) {
return _state == State.Cancelled;
}
}
public boolean isDone() {
synchronized (_lock) {
return _state == State.Resolved;
}
}
public T get() throws InterruptedException, CancellationException {
while (_state == State.Empty) {
synchronized (_lock) {
_lock.wait();
}
}
if (_state == State.Resolved)
return _result;
else
throw new CancellationException();
}
}
I would probably make interface public but implementation ResultHandlerImpl package-private so it would be harder for the users to mess up with implementation details. Then in callback methods I'd pass my callback ResultHandler as a parameter (actually it obviously would be a ResultHandlerImpl):
public interface LoginCallback {
void askForPassword(ResultHandler<String> resultHandler);
}
And my login method would look something like this (assuming you have private methods tryRestoreSession that doesn't need password and loginWithPassword that requires):
public boolean login(final LoginCallback loginCallback) {
if (tryRestoreSession()) {
return true;
} else {
final ResultHandlerImpl<String> passwordHandler = new ResultHandlerImpl<>();
Handler handler = new Handler(getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
// run in the main thread
loginCallback.askForPassword(passwordHandler);
}
});
String password;
try {
password = passwordHandler.get();
} catch (CancellationException e) {
return false;
} catch (InterruptedException e) {
return false;
}
return loginWithPassword(password);
}
}
What I think is important here:
I think that passing a callback to LoginCallback makes it easier to write an asynchronous UI-based implementation using standard Java.
ResultHandlerImpl has cancel method. So if the user, for example, forgot the password there is a way to cancel whole login process and not get stuck with a background thread waiting for a password forever
ResultHandlerImpl uses explicit synchronization and wait/notifyAll to establish happens-before relationship between actions on different threads to avoid.
ResultHandlerImpl uses wait/notifyAll so the background thread doesn't consume CPU (and battery) while waiting for the UI.
UPDATED using "wait and notify" instead of looping
UPDATED 2 synchronized methods
Finally I end up with object wrapper(thansk to #SergGr ) and handler
class ObjectWrapper<T> {
T object;
boolean ready;
synchronized void set(T object) {
this.object = object;
this.ready = true;
notifyAll();
}
T get() {
while (!ready) {
synchronized(this) {
try {
wait();
} catch (InterruptedException e) {
return null;
}
}
}
return object;
}
}
In my network thread
Handler handler = new Handler(getMainLooper());
ObjectWarpper<String> wrapper = new ObjectWarpper<>();
handler.post(() -> wrapper.set(askForPassword()));
String password = wrapper.get();
Related
I have a need to run some threads concurrently, but need to force each process to run in a new Thread (this is due to some ThreadLocal bleed that I don't have full control over). To do so, I have been using the SimpleAsyncTaskExecutor. However, the issue with this is that it doesn't maintain a queue that allows new tasks to be submitted once it's reached the concurrency limit. What I really need to do is have functionality like the SimpleAsyncTaskExecutor but where tasks can still be submitted even after the concurrency limit has been reached - I just want those tasks to wait in the queue until another slot frees up. This is what I have right now:
SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
taskExecutor.setConcurrencyLimit(maxThreads);
return taskExecutor;
Is there some out-of-the-box solution for this, or do I need to write something custom?
To ensure you need to execute every task in a new Thread, You are basically against use of any ThreadPool (ThreadLocal behavior in a ThreadPool is something you need to get rid of, sooner or later).
To overcome this, you can simply produce something like this,
class ThreadPerTaskExecutor implements Executor {
public void execute(Runnable r) {
Thread t = new Thread(r);
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
which executes the Runnable always in a new Thread.
Coming to a crude implementation, We can do something like
final Executor executor = new ThreadPerTaskExecutor();
final ExecutorService service = Executors.newFixedThreadPool(3);
for (int i = 0; i < 100; i++) {
service.submit(new Runnable() {
public void run() {
try {
System.out.println("Executed inside Thread pool with concurrency level 3"
+ Thread.currentThread().toString());
executor.execute(new Runnable() {
public void run() {
try {
Thread.sleep(3000); //Some expensive operations here.
System.out.println(
"Executed inside new Thread always" + Thread.currentThread().toString());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
This can be improved with lambdas as well after Java 8. Hope this sheds the basic idea.
Is there some out-of-the-box solution for this, or do I need to write something custom?
I think there is no out-of-the-box solution for this, and you need to write your own code for this.
You can extend the SimpleAsyncTaskExecutor for simpler/quicker implementation. Example:
public class SimpleAsyncQueueTaskExecutor extends SimpleAsyncTaskExecutor {
private Queue<Runnable> queue = new ConcurrentLinkedQueue<Runnable>();
private AtomicInteger concurrencyValue = new AtomicInteger(0);
private void checkAndExecuteFromQueue() {
int count = concurrencyValue.get();
if (isThrottleActive() && !queue.isEmpty() &&
(count < getConcurrencyLimit())) {
Runnable task = queue.poll();
concurrencyValue.incrementAndGet();
doExecute(new ConcurrencyThrottlingRunnable(task));
}
}
private void afterExecute(Runnable task) {
queue.remove(task);
concurrencyValue.decrementAndGet();
// Check and execute other tasks
checkAndExecuteFromQueue();
}
#Override
public void execute(Runnable task, long startTimeout) {
Assert.notNull(task, "Runnable must not be null");
if (isThrottleActive() && startTimeout > TIMEOUT_IMMEDIATE) {
queue.offer(task);
checkAndExecuteFromQueue();
} else {
doExecute(task);
}
}
private class ConcurrencyThrottlingRunnable implements Runnable {
private final Runnable target;
public ConcurrencyThrottlingRunnable(Runnable target) {
this.target = target;
}
#Override
public void run() {
try {
this.target.run();
}
finally {
afterExecute(this.target);
}
}
}
This example code just add a queue, and override the execute method.
Hope this help.
I don't know if there are any other good ways to achieve the results I want, thank you.
I have a requirement, according to the URL, create multiple webview threads, and execute them in order, such as thread execution, then trigger thread two execution, and so on, I use the synchronized (lobject) method, but in JAVAfx encountered a problem, the code is as follows:
public class LockObject {
public int orderNum = 1;
public final static int MaxValue=9;
public LockObject(int orderNum){
this.orderNum = orderNum;
}
}
public class DownloadThread extends Thread{
private LockObject lobject;
private int printNum =0;
private String url;
public DownloadThread(LockObject lobject,int printNum,String url){
this.lobject=lobject;
this.printNum = printNum;
this.url = url;
}
#Override
public void run() {
synchronized(lobject){
while(lobject.orderNum <= lobject.MaxValue){
if(lobject.orderNum == printNum){
System.out.print(printNum);
Platform.runLater(new Runnable() {
#Override
public void run() {
webView.getEngine().load(url);
webView.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
#Override
public void changed(ObservableValue<? extends Worker.State> observable, Worker.State oldValue, Worker.State newValue) {
if (newValue == Worker.State.SUCCEEDED) {
try {
//xxxxx
// java.lang.IllegalMonitorStateException
lobject.notifyAll();
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
});
lobject.orderNum++;
if(lobject.orderNum==downloadThreads.length){
saveCsvFile(goodCSVS);
}
//lobject.notifyAll(); is ok
}else{
try {
lobject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
Place of call
private DownloadThread[] downloadThreads;
LockObject lobject = new LockObject(1);
downloadThreads = new DownloadThread[tableView.getItems().size()];
for (int i = 0; i < tableView.getItems().size(); i++) {
UrlModel item = tableView.getItems().get(i);
downloadThreads[i] = new DownloadThread(lobject,tableView.getItems().size()-i,item.getLink());
downloadThreads[i].start();
}
Calling lobject.notifyAll() in the run method in Platform.runLater will report an IllegalMonitorStateException. After the address is processed, I want to wake up the next thread to execute.
If you need to execute multiple tasks in order, there's no need to create multiple threads. Just using a single thread will guarantee the next task only executes after the previous one has completed. You should also consider using a CountDownLatch instead of synchronizing on an object.
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
for (UrlModel model : tableView.getItems()) {
executor.submit(() -> {
CountDownLatch latch = new CountDownLatch(1);
Platform.runLater(() -> {
engine.load(model.getLink())
engine.getLoadWorker().runningProperty().addListener((obs, ov, nv) -> {
if (!nv) {
latch.countDown();
}
});
});
latch.await();
// do whatever needs to happen after the WebEngine finishes loading
return null; // using #submit(Callable) and Callable needs to return something
});
}
} finally {
executor.shutdown();
}
Some notes:
You may want to avoid creating the ExecutorService if the table has no items to process. That is, assuming you don't reuse the same ExecutorService every time.
If you reuse the ExecutorService, don't call shutdown().
This ExecutorService uses non-daemon threads. You can customize this by supplying a ThreadFactory that creates daemon threads.
I added a listener to the Worker#running property instead of the status property to make it easier to ensure countDown() is invoked no matter the terminal status of the load (i.e. whether it's SUCCEEDED, CANCELLED or FAILED).
You may want to remove the the listener added to the Worker's property when it's finished. You can do this by using an anonymous class (rather than the lambda expression I used) and calling obs.removeListener(this) inside the changed method, where obs is the ObservableValue argument.
I'm doing an exercise about Java concurrency using wait, notify to study for an exam.
The exam will be written, so the code does have to be perfect since we can't try to compile and check errors.
This is the text of the exercise:
General idea:
when the downloader is instanced the queue and the hashmap are created and passed to all the threads. (shared data)
the download method add the url to the queue and call notifyAll to wake up the Downloader Threads.
the getData method waits until there are data in the hashmap for the provided url. When data are available it returns to the caller.
the downloader thread runs an infinity loop. It waits until an url is present in the queue. When it receives an url it downloads it and puts the bytes in the hashmap calling notifyAll to wake up a possible user waiting in getData method.
This is the code that I produced:
public class Downloader{
private Queue downloadQueue;
private HashMap urlData;
private final static THREADS_NUMBER;
public Downloader(){
this.downloadQueue = new Queue();
this.urlData = new HashMap();
for(int i = 0; i < THREADS_NUMBER; i++){
new DownTh(this.downloadQueue, this.urlData).start();
}
}
void syncronized download(String URL){
downloadQueue.add(url);
notifyAll();
return;
}
byte[] syncronized getData(String URL){
while(urlData.get(URL) == null ){
wait()
}
return urlData.get(URL);
}
}
public class DownTh extend Thread{
private Queue downloadQueue;
private HashMap urlData;
public DownTh(Queue downloadQueue, HashMap urlData){
this.downloadQueue = downloadQueue
this.urlData = urlData;
}
public void run(){
while(true){
syncronized{
while(queue.isEmpty()){
wait()
}
String url = queue.remove();
urlData.add(url, Util.download(url))
notifyAll()
}
}
}
}
Can you help me and tell me if the logic is right?
Let's assume for a second that all those great classes in Java that handle synchronization do not exist, because this is a synthetic task, and all you got to handle is sychronized, wait and notify.
The first question to answer in simple words is: "Who is going to wait on what?"
The download thread is going to wait for an URL to download.
The caller is going to wait for the result of that download thread.
What does this mean in detail? We need at least one synchronization element between the caller and the download thread (your urlData), also there should be one data object handling the download data itself for convenience, and to check whether or not the download has yet been completed.
So the detailed steps that will happen are:
Caller requests new download.create: DownloadResultwrite: urlData(url -> DownloadResult)wake up 1 thread on urlData.
Thread X must find data to download and process it or/then fall asleep again.read: urlData (find first unprocessed DownloadResult, otherwise wait on urlData)write: DownloadResult (acquire it)write: DownloadResult (download result)notify: anyone waiting on DownloadResultrepeat
Caller must be able to asynchronously check/wait for download result.read: urlDataread: DownloadResult (wait on DownloadResult if required)
As there are reads and writes from different threads on those objects, synchronization is required when accessing the objects urlData or DownloadResult.
Also there will be a wait/notify association:
caller -> urlData -> DownTh
DownTh -> DownloadResult -> caller
After careful analysis the following code would fulfill the requirements:
public class DownloadResult {
protected final URL url; // this is for convenience
protected boolean inProgress;
protected byte[] result;
public DownloadResult(final URL url) {
this.url = url;
this.inProgress = false;
}
/* Try to lock this against tother threads if not already acquired. */
public synchronized boolean acquire() {
if (this.inProgress == false) {
this.inProgress = true;
return true;
} else {
return false;
}
}
public void download() {
final byte[] downloadedBytes = Util.download(this.url); // note how this is done outside the synchronized block to avoid unnecessarily long blockings
synchronized (this) {
this.result = downloadedBytes;
this.notifyAll(); // wake-up ALL callers
}
}
public synchronized byte[] getResult() throws InterruptedException {
while (this.result == null) {
this.wait();
}
return this.result;
}
}
protected class DownTh extends Thread {
protected final Map<URL, DownloadResult> urlData;
public DownTh(final Map<URL, DownloadResult> urlData) {
this.urlData = urlData;
this.setDaemon(true); // this allows the JVM to shut down despite DownTh threads still running
}
protected DownloadResult getTask() {
for (final DownloadResult downloadResult : urlData.values()) {
if (downloadResult.acquire()) {
return downloadResult;
}
}
return null;
}
#Override
public void run() {
DownloadResult downloadResult;
try {
while (true) {
synchronized (urlData) {
while ((downloadResult = this.getTask()) == null) {
urlData.wait();
}
}
downloadResult.download();
}
} catch (InterruptedException ex) {
// can be ignored
} catch (Error e) {
// log here
}
}
}
public class Downloader {
protected final Map<URL, DownloadResult> urlData = new HashMap<>();
// insert constructor that creates the threads here
public DownloadResult download(final URL url) {
final DownloadResult result = new DownloadResult(url);
synchronized (urlData) {
urlData.putIfAbsent(url, result);
urlData.notify(); // only one thread needs to wake up
}
return result;
}
public byte[] getData(final URL url) throws InterruptedException {
DownloadResult result;
synchronized (urlData) {
result = urlData.get(url);
}
if (result != null) {
return result.getResult();
} else {
throw new IllegalStateException("URL " + url + " not requested.");
}
}
}
In real Java things would be done differently, by using Concurrent classes and/or Atomic... classes, so this is just for educational purposes. For further reading see "Callable Future".
I have got a class that records eyetracking data asynchronously. There are methods to start and stop the recording process. The data is collected in a collection and the collection can only be accessed if the recording thread has finished its work. It basically encapsulates all the threading and synchronizing so the user of my library doesn't have to do it.
The heavily shortened code (generics and error handling omitted):
public class Recorder {
private Collection accumulatorCollection;
private Thread recordingThread;
private class RecordingRunnable implements Runnable {
...
public void run() {
while(!Thread.currentThread().isInterrupted()) {
// fetch data and collect it in the accumulator
synchronized(acc) { acc.add(Eyetracker.getData()) }
}
}
}
public void start() {
accumulatorCollection = new Collection();
recordingThread = new Thread(new RecordingRunnable(accumulatorCollection));
recordingThread.start();
}
public void stop() {
recordingThread.interrupt();
}
public void getData() {
try {
recordingThread.join(2000);
if(recordingThread.isAlive()) { throw Exception(); }
}
catch(InterruptedException e) { ... }
synchronized(accumulatorCollection) { return accumulatorCollection; }
}
}
The usage is quite simple:
recorder.start();
...
recorder.stop();
Collection data = recorder.getData();
My problem with the whole thing is how to test it. Currently i am doing it like this:
recorder.start();
Thread.sleep(50);
recorder.stop();
Collection data = recorder.getData();
assert(stuff);
This works, but it is non-deterministic and slows down the test suite quite a bit (i marked these tests as integration tests, so they have to be run separately to circumvent this problem).
Is there a better way?
There is a better way using a CountDownLatch.
The non-deterministic part of the test stems from two variables in time you do not account for:
creating and starting a thread takes time and the thread may not have started executing the runnable when Thread.start() returns (the runnable will get executed, but it may be a bit later).
the stop/interrupt will break the while-loop in the Runnable but not immediately, it may be a bit later.
This is where a CountDownLatch comes in: it gives you precise information about where another thread is in execution. E.g. let the first thread wait on the latch, while the second "counts down" the latch as last statement within a runnable and now the first thread knows that the runnable finished. The CountDownLatch also acts as a synchronizer: whatever the second thread was writing to memory, can now be read by the first thread.
Instead of using an interrupt, you can also use a volatile boolean. Any thread reading the volatile variable is guaranteed to see the last value set by any other thread.
A CountDownLatch can also be given a timeout which is useful for tests that can hang: if you have to wait to long you can abort the whole test (e.g. shutdown executors, interrupt threads) and throw an AssertionError. In the code below I re-used the timeout to wait for a certain amount of data to collect instead of 'sleeping'.
As an optimization, use an Executor (ThreadPool) instead of creating and starting threads. The latter is relative expensive, using an Executor can really make a difference.
Below the updated code, I made it runnable as an application (main method). (edit 28/02/17: check maxCollect > 0 in while-loop)
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
public class Recorder {
private final ExecutorService executor;
private Thread recordingThread;
private volatile boolean stopRecording;
private CountDownLatch finishedRecording;
private Collection<Object> eyeData;
private int maxCollect;
private final AtomicBoolean started = new AtomicBoolean();
private final AtomicBoolean stopped = new AtomicBoolean();
public Recorder() {
this(null);
}
public Recorder(ExecutorService executor) {
this.executor = executor;
}
public Recorder maxCollect(int max) { maxCollect = max; return this; }
private class RecordingRunnable implements Runnable {
#Override public void run() {
try {
int collected = 0;
while (!stopRecording) {
eyeData.add(EyeTracker.getData());
if (maxCollect > 0 && ++collected >= maxCollect) {
stopRecording = true;
}
}
} finally {
finishedRecording.countDown();
}
}
}
public Recorder start() {
if (!started.compareAndSet(false, true)) {
throw new IllegalStateException("already started");
}
stopRecording = false;
finishedRecording = new CountDownLatch(1);
eyeData = new ArrayList<Object>();
// the RecordingRunnable created below will see the values assigned above ('happens before relationship')
if (executor == null) {
recordingThread = new Thread(new RecordingRunnable());
recordingThread.start();
} else {
executor.execute(new RecordingRunnable());
}
return this;
}
public Collection<Object> getData(long timeout, TimeUnit tunit) {
if (started.get() == false) {
throw new IllegalStateException("start first");
}
if (!stopped.compareAndSet(false, true)) {
throw new IllegalStateException("data already fetched");
}
if (maxCollect <= 0) {
stopRecording = true;
}
boolean recordingStopped = false;
try {
// this establishes a 'happens before relationship'
// all updates to eyeData are now visible in this thread.
recordingStopped = finishedRecording.await(timeout, tunit);
} catch(InterruptedException e) {
throw new RuntimeException("interrupted", e);
} finally {
stopRecording = true;
}
// if recording did not stop, do not return the eyeData (could stil be modified by recording-runnable).
if (!recordingStopped) {
throw new RuntimeException("recording");
}
// only when everything is OK this recorder instance can be re-used
started.set(false);
stopped.set(false);
return eyeData;
}
public static class EyeTracker {
public static Object getData() {
try { Thread.sleep(1); } catch (Exception ignored) {}
return new Object();
}
}
public static void main(String[] args) {
System.out.println("Starting.");
ExecutorService exe = Executors.newSingleThreadExecutor();
try {
Recorder r = new Recorder(exe).maxCollect(50).start();
int dsize = r.getData(2000, TimeUnit.MILLISECONDS).size();
System.out.println("Collected " + dsize);
r.maxCollect(100).start();
dsize = r.getData(2000, TimeUnit.MILLISECONDS).size();
System.out.println("Collected " + dsize);
r.maxCollect(0).start();
Thread.sleep(100);
dsize = r.getData(2000, TimeUnit.MILLISECONDS).size();
System.out.println("Collected " + dsize);
} catch (Exception e) {
e.printStackTrace();
} finally {
exe.shutdownNow();
System.out.println("Done.");
}
}
}
Happy coding :)
I want to make a single thread which would contain 3 infinite tasks.
I want one task to run at a time and start/stop running task when required.
For example first I want task 1 to run, then I want task 2 to run but after stopping task 1 and again I want task 1 to run but after stopping of task 2 and so on.
Infinite task needs to check some condition and if that condition is satisfied perform some operations and if not satisfied sleep for few seconds and after wake up perform the above same operations again.
Infinite Runnable task looks some thing like this:
new Runnable(){
while(1){
if(TaskQueue.getInstance().size()<= 100){
TaskQueue.getInstance().push("add command to the end of queue");
}else{
try {
Thread.sleep(10000);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Any help would be appreciated?
Edit : I modified my question. I want a continuous single running thread(some thing like looper ) to monitor 3 infinite tasks and control this single continuous running thread tasks from outside.
Use this for start/stop thread in real-time:
class MyThread extends Thread {
private volatile boolean running = true; // Run unless told to pause
...
#Override
public void run() {
// Only keep painting while "running" is true
// This is a crude implementation of pausing the thread
while (true) {
if (Thread.currentThread().isInterrupted()) {
return;
}
if (running) {
//Your code
} else yield;
}
}
public void pauseThread() throws InterruptedException {
running = false;
}
public void resumeThread() {
running = true;
}
}
For pause thread use this:
myThread.pauseThread();
For resume thread use this:
myThread.resumeThread();
For stop thread use this (Not recommended):
myThread.stop();
For currently stop thread use this:
myThread.interrupt();
You must use a class like Thread that already implements Runnable.
new Thread(){....};
And the way it works it's:
Thread t = new Thread(){.....};
t.start();
t.stop();
You could also initialize a new thread, like:
Thread exampleThread = new thread();
After this you can start it at any point in your code by:
exampleThread.start();
you can use Semaphore,
to Manage the amount of signal.
private final static Semaphore semaphore = new Semaphore(0);
public static void main(String[] args) throws Exception {
//入口
threadTest();
}
public static void thread1() {
try{
//…… some code
}
finally{
semaphore.release();
}
}
public static void thread2() {
semaphore.acquire(1);
}
The question is my first answer,thanks.
I finally made my task scheduler. The API of which looks something like this:
TaskScheduler taskScheduler = TaskScheduler.getInstance();
taskScheduler.startTaskOne();
taskScheduler.stopTaskOne();
taskScheduler.startTaskTwo();
taskScheduler.stopTaskTwo();
Runs one task at a time (because I used Executors.newSingleThreadExecutor()).
We can control the execution of the task from outside:
public class TaskScheduler {
private static ExecutorService mTaskRunningService;
private static TaskScheduler mInstance;
private Future mFirstTaskFuture = null;
private Future mSecondTaskFuture = null;
static {
configure();
}
private static void configure() {
mTaskRunningService = Executors.newSingleThreadExecutor();
}
public static TaskScheduler getInstance() {
if (mInstance == null) {
mInstance = new TaskScheduler();
}
return mInstance;
}
private Runnable mTaskOneRunnable = new Runnable() {
#Override
public void run() {
try {
while (true) {
/** stop this single thread (i.e executing one task at time) service if this thread is interrupted
* from outside because documentation of {#link java.util.concurrent.ThreadPoolExecutor#shutdownNow()}
* says we need to do this*/
if (Thread.currentThread().isInterrupted()) {
return;
}
// task one work.......
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
private Runnable mTaskTwoRunnable = new Runnable() {
#Override
public void run() {
try {
while (true) {
/** stop this single thread (i.e executing one task at time) service if this thread is interrupted
* from outside because documentation of {#link java.util.concurrent.ThreadPoolExecutor#shutdownNow()}
* says we need to do this*/
if (Thread.currentThread().isInterrupted()) {
return;
}
// task two work......
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
public synchronized void startTaskOne() {
if (mFirstTaskFuture == null) {
// start executing runnable
mFirstTaskFuture = mTaskRunningService.submit(mTaskOneRunnable);
}
}
public synchronized boolean stopTaskOne() {
if (mFirstTaskFuture != null) {
// stop general reading thread
mFirstTaskFuture.cancel(true);
// cancel status
boolean status = mFirstTaskFuture.isDone();
// assign null because startTaskOne() again be called
mGeneralFuture = null;
return status;
}
return true;
}
public synchronized void startTaskTwo() {
if (mSecondTaskFuture == null) {
// start executing runnable
mSecondTaskFuture = mTaskRunningService.submit(mTaskTwoRunnable);
}
}
public synchronized boolean stopTaskTwo() {
if (mSecondTaskFuture != null) {
// clear task queue
mTaskQueue.clearTaskQueue();
// stop 22 probes reading thread
mSecondTaskFuture.cancel(true);
// cancel status
boolean status = mSecondTaskFuture.isDone();
// assign null because startTaskTwo() again be called
mSecondTaskFuture = null;
return status;
}
return true;
}
}