Synchronizing issue: I want the main thread to be run before another thread but it sometimes doesn´t
- by Rox
I have done my own small concurrency framework (just for learning purposes) inspired by the java.util.concurrency package. This is about the Callable/Future mechanism. My code below is the whole one and is compilable and very easy to understand.
My problem is that sometimes I run into a deadlock where the first thread (the main thread) awaits for a signal from the other thread. But then the other thread has already notified the main thread before the main thread went into waiting state, so the main thread cannot wake up.
FutureTask.get() should always be run before FutureTask.run() but sometimes the run() method (which is called by new thread) runs before the get() method (which is called by main thread). I don´t know how I can prevent that.
This is a pseudo code of how I want the two threads to be run.
//From main thread:
Executor.submit().get() (in get() the main thread waits for new thread to notify)
->submit() calls Executor.execute(FutureTask object)
-> execute() starts new thread
-> new thread shall notify `main thread`
I cannot understand how the new thread can start up and run faster than the main thread that actually starts the new thread.
Main.java:
public class Main {
public static void main(String[] args) {
new ExecutorServiceExample();
}
public Main() {
ThreadExecutor executor = new ThreadExecutor();
Integer i = executor.submit(new Callable<Integer>() {
@Override
public Integer call() {
return 10;
}
}).get();
System.err.println("Value: "+i);
}
}
ThreadExecutor.java:
public class ThreadExecutor {
public ThreadExecutor() {}
protected <V> RunnableFuture<V> newTaskFor(Callable c) {
return new FutureTask<V>(c);
}
public <V> Future<V> submit(Callable<V> task) {
if (task == null)
throw new NullPointerException();
RunnableFuture<V> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
public void execute(Runnable r) {
new Thread(r).start();
}
}
FutureTask.java:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
public class FutureTask<V> implements RunnableFuture<V> {
private Callable<V> callable;
private volatile V result;
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public FutureTask(Callable callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
}
@Override
public void run() {
acquireLock();
System.err.println("RUN"+Thread.currentThread().getName());
V v = this.callable.call();
set(v);
condition.signal();
releaseLock();
}
@Override
public V get() {
acquireLock();
System.err.println("GET "+Thread.currentThread().getName());
try {
condition.await();
} catch (InterruptedException ex) {
Logger.getLogger(FutureTask.class.getName()).log(Level.SEVERE, null, ex);
}
releaseLock();
return this.result;
}
public void set(V v) {
this.result = v;
}
private void acquireLock() {
lock.lock();
}
private void releaseLock() {
lock.unlock();
}
}
And the interfaces:
public interface RunnableFuture<V> extends Runnable, Future<V> {
@Override
void run();
}
public interface Future<V> {
V get();
}
public interface Callable<V> {
V call();
}