I want to synchronize one method or one block based on input parameters.
So I have one API which has two inputs (let's say id1 and id2) of long type (could be primitive or wrapper) in post payload, which can be JSON. This API will be called by multiple threads at the same time or at different times randomly.
Now if the first API call has id1=1 and id2=1, and at the same time another API call has id1=1 and id2=1, it should wait for the first API call to finish processing before executing the second call. If the second API call has a different combination of values like id1=1 and id2=2, it should go through parallel without any wait time.
I don't mind creating a service method also which the API resource method can call, rather than handling directly at API resource method.
I'm using Spring boot Rest Controlller APIs.
**Edit**
I've already tried using map as suggested but this partially works. It waits for all input values, not just the same input values. Below is my code:
public static void main(String[] args) throws Exception {
ApplicationContext context = SpringApplication.run(Application.class, args);
AccountResource ar = context.getBean(AccountResource.class);
UID uid1 = new UID();
uid1.setFieldId(1);
uid1.setLetterFieldId(1);
UID uid2 = new UID();
uid2.setFieldId(2);
uid2.setLetterFieldId(2);
UID uid3 = new UID();
uid3.setFieldId(1);
uid3.setLetterFieldId(1);
Runnable r1 = new Runnable() {
#Override
public void run() {
while (true) {
ar.test(uid1);
}
}
};
Runnable r2 = new Runnable() {
#Override
public void run() {
while (true) {
ar.test(uid2);
}
}
};
Runnable r3 = new Runnable() {
#Override
public void run() {
while (true) {
ar.test(uid3);
}
}
};
Thread t1 = new Thread(r1);
t1.start();
Thread t2 = new Thread(r2);
t2.start();
Thread t3 = new Thread(r3);
t3.start();
}
#Path("v1/account")
#Service
public class AccountResource {
public void test(UID uid) {
uidFieldValidator.setUid(uid);
Object lock;
synchronized (map) {
lock = map.get(uid);
if (lock == null) {
map.put(uid, (lock = new Object()));
}
synchronized (lock) {
//some operation
}
}
}
}
package com.urman.hibernate.test;
import java.util.Objects;
public class UID {
private long letterFieldId;
private long fieldId;
private String value;
public long getLetterFieldId() {
return letterFieldId;
}
public void setLetterFieldId(long letterFieldId) {
this.letterFieldId = letterFieldId;
}
public long getFieldId() {
return fieldId;
}
public void setFieldId(long fieldId) {
this.fieldId = fieldId;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#Override
public int hashCode() {
return Objects.hash(fieldId, letterFieldId);
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
UID other = (UID) obj;
return fieldId == other.fieldId && letterFieldId == other.letterFieldId;
}
}
You need a collection of locks, which you can keep in a map and allocate as required. Here I assume that your id1 and id2 are Strings; adjust as appropriate.
Map<String,Object> lockMap = new HashMap<>();
:
void someMethod(String id1, String id2) {
Object lock;
synchronized (lockMap) {
lock = lockMap.get(id1+id2);
if (lock == null) lockMap.put(id1+id2, (lock = new Object()));
}
synchronized (lock) {
:
}
}
You need a little bit of 'global' synchronization for the map operations, or you could use one of the concurrent implementations. I used the base HashMap for simplicity of implementation.
After you've selected a lock, sync on it.
I'm writing a small program to help me learn some multithreading in java, and I'm stuck on how to implement some scenario.
The program simulates a gas station that also has a coffee house in it.
I want to be able to create the following scenario:
add a person to a gas pump queue.
at the same time add a person to a cashier queue in the coffee house.
if the person's turn in the pump queue arrives before the turn in the cashier queue, allow him to choose what to do (stay in cashier queue and quit the pump queue or the other way around).
How can I jump between these 2 states?
So far I have this:
The Person class
public class Person implements Runnable {
private GasPump pump;
private Cashier cashier;
...
public void pumpGas() throws InterruptedException {
synchronized (this) {
pump.addCarToQueue(this);
wait();
}
synchronized (pump) {
sleep((long) (Math.random() * 5000));
pump.notify();
}
}
public void buyCoffee() throws InterruptedException {
synchronized (this) {
cashier.addCustomerToQueue(this); // standing inline
wait();
}
synchronized (cashier) {
sleep((long) (Math.random() * 5000)); // paying at cashier
cashier.notify();
}
}
...
}
The GasPump class
public class GasPump implements Runnable {
private Queue<Person> cars;
...
#Override
public void run() {
while (gasStation.isOpen()) {
if (!cars.isEmpty()) {
Car firstCar = cars.poll();
if (firstCar != null) {
synchronized (firstCar) {
firstCar.notifyAll();
}
} else {
// ?
}
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
...
}
And the Cashier class
public class Cashier implements Runnable {
private Queue<Person> customers;
...
#Override
public void run() {
while(coffeeHouse.isOpen()){
if(!customers.isEmpty()){
Car firstCustomer = customers.poll();
if(firstCustomer != null){
synchronized (firstCustomer) {
firstCustomer.notifyAll();
}
}
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
...
}
You should avoid using wait and notify as it is difficult to use them correctly and efficiently - use the classes from java.util.concurrent instead.
What I would do: add two boolean flags to your Person: hasPumped and hasShopped - once a person pumps their gas or shops then you set the appropriate flag to true.
Replace your Queues with BlockingQueues (probably the LinkedBlockingQueue is appropriate here) - this is a thread-safe queue, and you can call take on it in order to block until the queue is non-empty (rather than polling and then sleeping if the queue is empty). If you prefer to poll and sleep then you may want to use a ConcurrentLinkedQueue instead, though I advise that you use take on a BlockingQueue instead.
Add a Person to the GasPump and Cashier queues. When the person is removed from the queue via take or poll, then check its hasPumped or hasShopped flag to determine if any additional action is needed, for example if the Cashier takes the person and hasPumped is true then there's no need to ask the Person if they want to continue waiting in the gas queue since they've already finished pumping.
If the person chooses to quit a queue, then call remove(person) on the appropriate queue.
When the person finishes pumping gas then put them in the cashier queue if their hasShopped flag is false, and likewise put them in the gas queue when they've finished shopping if their hasPumped flag is false.
You shouldn't need any synchronized blocks or methods with this implementation.
public class Person implements Runnable {
private GasPump pump;
private Cashier cashier;
private boolean hasPumped, hasShopped, readyToPump, readyToShop;
private Thread thread;
public void run() {
thread = Thread.getCurrentThread();
while(!hasPumped && !hasShopped) {
try {
readyToPump = false;
readyToShop = false;
if (!hasPumped)
pumpGas();
if(!hasShopped)
buyCoffee();
thread.sleep(FOREVER);
} catch (InterruptedException ex) {
// check flags to see what to do next
}
}
}
public void pumpGas() {
pump.addCarToQueue(this);
}
public void buyCoffee() {
cashier.addCustomerToQueue(this);
}
public void setReadyToPump() {
readyToPump = true;
thread.interrupt();
}
public void setReadyToShop() {
readyToShop = true;
thread.interrupt();
}
}
public class GasPump implements Runnable {
private BlockingQueue<Person> cars = new LinkedBlockingQueue<>();
#Override
public void run() {
while (gasStation.isOpen()) {
Person person = cars.take();
person.setReadyToPump();
}
// clean up persons in queue
}
}
public class Cashier implements Runnable {
private BlockingQueue<Person> customers = new LinkedBlockingQueue();
#Override
public void run() {
while(coffeeHouse.isOpen()){
Person person = customers.take();
person.setReadyToShop();
}
// clean up persons in queue
}
}
I cannot understand why I am getting deadlock in this simple sample.What is wrong with it?
public static void main(String[] args) {
Object data = null;
new Thread(new Producer(data)).start();
new Thread(new Consumer(data)).start();
}
}
class Producer implements Runnable {
private Object data;
public Producer(Object data) {
this.data = data;
}
#Override
public void run() {
while (true) {
while (data != null) {}
data = new Object();
System.out.println("put");
}
}
}
class Consumer implements Runnable {
private Object data;
public Consumer(Object data) {
this.data = data;
}
#Override
public void run() {
while (true) {
while (data == null) { }
data = null;
System.out.println("get");
}
}
There are two problems.
1: You have two separate Runnables that each have their own private internal member named data. Changes made to one aren't visible to the other. If you want to pass data between two threads, you need to store it in a common place where they both access it. You also need to either synchronize around the accesses or make the reference volatile.
2: Your checks seem to be inverted. You probably want to null it when it's not null, and create one when it is null? Its tough to tell what you want it to actually do there! :)
public static volatile Object data;
public static void main(String[] args) {
data = null;
new Thread(new Producer(data)).start();
new Thread(new Consumer(data)).start();
}
}
class Producer implements Runnable {
public Producer(Object data) {
this.data = data;
}
#Override
public void run() {
while (true) {
while (data == null) {}
data = new Object();
System.out.println("put");
}
}
}
class Consumer implements Runnable {
public Consumer(Object data) {
this.data = data;
}
#Override
public void run() {
while (true) {
while (data != null) { }
data = null;
System.out.println("get");
}
}
(Also this isn't really an example classically what we'd define as a deadlock, where two threads can't proceed because they both want locks the other has. There are no locks here. This is an example of two infinite loops that just don't do anything.)
Each instance has its own data field.
The consumer never sees the producer's changes.
The consumer and producer have separate data fields, so the consumer will never get any data to consume.
Also, spinlocking a consumer/producer on a field isn't generally a good idea, you're much better off using mutexes or semaphores to signal the availability of data / the possibility to publish. If this is more than a test in the search of knowledge, you should really read up on how to use those two.
When your produced "produces", all it does is points its own data reference to the new object, and the consumer has no way of knowing what happened. What you can do instead is make another class
class Data {
private Object data = null;
synchronized void set( Object data ){ this.data = data; }
synchronized Object get(){ return data; }
}
Then in your main do
Data data = new Data();
Pass the 'Data' object to the consumer and producer, and use the get/set methods instead of assignment.
That way, both consumer and producer will be pointing to the same Data object and when the producer produces or the consumer consumes, they will be changing the reference in the Data object, which they are sharing.
I think this should do what you intend (it is still bad code):
public class Example {
public static void main(String[] args) {
Consumer consumer = new Consumer();
new Thread(new Producer(consumer)).start();
new Thread(consumer).start();
}
}
class Producer implements Runnable {
private final Consumer consumer;
public Producer(Consumer consumer) {
this.consumer = consumer;
}
#Override
public void run() {
while (true) {
while (consumer.data != null) {}
consumer.data = new Object();
System.out.println("put");
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
public volatile Object data;
#Override
public void run() {
while (true) {
while (data == null) {}
data = null;
System.out.println("get");
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
I think you should focus on the basics of Java, before you go for advanced topics such as parallel programming as the main error in you example (separate data fields) is very basic.
does anyone know how I can solve the following problem. I want to return a String from a callback, but I get only "The final local variable s cannot be assigned, since it is defined in an enclosing type", because of final.
public String getConstraint(int indexFdg) {
final String s;
AsyncCallback<String> callback = new AsyncCallback<String>() {
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
public void onSuccess(String result) {
s = result;
}
};
SpeicherService.Util.getInstance().getConstraint(indexFdg, callback);
return s;
}
The whole point of an asynchronous callback is to notify you of something that happens asynchronously, at some time in the future. You can't return s from getConstraint if it's going to be set after the method has finished running.
When dealing with asynchronous callbacks you have to rethink the flow of your program. Instead of getConstraint returning a value, the code that would go on to use that value should be called as a result of the callback.
As a simple (incomplete) example, you would need to change this:
String s = getConstraint();
someGuiLabel.setText(s);
Into something like this:
myCallback = new AsyncCallback<String>() {
public void onSuccess(String result) {
someGuiLabel.setText(result);
}
}
fetchConstraintAsynchronously(myCallback);
Edit
A popular alternative is the concept of a future. A future is an object that you can return immediately but which will only have a value at some point in the future. It's a container where you only need to wait for the value at the point of asking for it.
You can think of holding a future as holding a ticket for your suit that is at the dry cleaning. You get the ticket immediately, can keep it in your wallet, give it to a friend... but as soon as you need to exchange it for the actual suit you need to wait until the suit is ready.
Java has such a class (Future<V>) that is used widely by the ExecutorService API.
An alternative workaround is to define a new class, called SyncResult
public class SyncResult {
private static final long TIMEOUT = 20000L;
private String result;
public String getResult() {
long startTimeMillis = System.currentTimeMillis();
while (result == null && System.currentTimeMillis() - startTimeMillis < TIMEOUT) {
synchronized (this) {
try {
wait(TIMEOUT);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return result;
}
public void setResult(String result) {
this.result = result;
synchronized (this) {
notify();
}
}
}
Then change your code to this
public String getConstraint(int indexFdg) {
final SyncResult syncResult = new SyncResult();
AsyncCallback<String> callback = new AsyncCallback<String>() {
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
public void onSuccess(String result) {
syncResult.setResult(result);
}
};
SpeicherService.Util.getInstance().getConstraint(indexFdg, callback);
return syncResult.getResult();
}
The getResult() method will be blocked until setResult(String) method been called or the TIMEOUT reached.
This question is related to my question on existing coroutine implementations in Java. If, as I suspect, it turns out that there is no full implementation of coroutines currently available in Java, what would be required to implement them?
As I said in that question, I know about the following:
You can implement "coroutines" as threads/thread pools behind the scenes.
You can do tricksy things with JVM bytecode behind the scenes to make coroutines possible.
The so-called "Da Vinci Machine" JVM implementation has primitives that make coroutines doable without
bytecode manipulation.
There are various JNI-based approaches to coroutines also possible.
I'll address each one's deficiencies in turn.
Thread-based coroutines
This "solution" is pathological. The whole point of coroutines is to avoid the overhead of threading, locking, kernel scheduling, etc. Coroutines are supposed to be light and fast and to execute only in user space. Implementing them in terms of full-tilt threads with tight restrictions gets rid of all the advantages.
JVM bytecode manipulation
This solution is more practical, albeit a bit difficult to pull off. This is roughly the same as jumping down into assembly language for coroutine libraries in C (which is how many of them work) with the advantage that you have only one architecture to worry about and get right.
It also ties you down to only running your code on fully-compliant JVM stacks (which means, for example, no Android) unless you can find a way to do the same thing on the non-compliant stack. If you do find a way to do this, however, you have now doubled your system complexity and testing needs.
The Da Vinci Machine
The Da Vinci Machine is cool for experimentation, but since it is not a standard JVM its features aren't going to be available everywhere. Indeed I suspect most production environments would specifically forbid the use of the Da Vinci Machine. Thus I could use this to make cool experiments but not for any code I expect to release to the real world.
This also has the added problem similar to the JVM bytecode manipulation solution above: won't work on alternative stacks (like Android's).
JNI implementation
This solution renders the point of doing this in Java at all moot. Each combination of CPU and operating system requires independent testing and each is a point of potentially frustrating subtle failure. Alternatively, of course, I could tie myself down to one platform entirely but this, too, makes the point of doing things in Java entirely moot.
So...
Is there any way to implement coroutines in Java without using one of these four techniques? Or will I be forced to use the one of those four that smells the least (JVM manipulation) instead?
Edited to add:
Just to ensure that confusion is contained, this is a related question to my other one, but not the same. That one is looking for an existing implementation in a bid to avoid reinventing the wheel unnecessarily. This one is a question relating to how one would go about implementing coroutines in Java should the other prove unanswerable. The intent is to keep different questions on different threads.
I would take a look at this: http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html, its pretty interesting and should provide a good place to start. But of course we are using Java so we can do better (or maybe worse because there are no macros :))
From my understanding with coroutines you usually have a producer and a consumer coroutine (or at least this is the most common pattern). But semantically you don't want the producer to call the consumer or visa-versa because this introduces an asymmetry. But given the way stack based languages work we will need to have someone do the calling.
So here is a very simple type hierarchy:
public interface CoroutineProducer<T>
{
public T Produce();
public boolean isDone();
}
public interface CoroutineConsumer<T>
{
public void Consume(T t);
}
public class CoroutineManager
{
public static Execute<T>(CoroutineProducer<T> prod, CoroutineConsumer<T> con)
{
while(!prod.IsDone()) // really simple
{
T d = prod.Produce();
con.Consume(d);
}
}
}
Now of course the hard part is implementing the interfaces, in particular it is difficult to break a computation into individual steps. For this you would probably want a whole other set of persistent control structures. The basic idea is that we want to simulate non-local transfer of control (in the end its kinda like we're simulating a goto). We basically want to move away from using the stack and the pc (program-counter) by keeping the state of our current operations in the heap instead of on the stack. Therefore we are going to need a bunch of helper classes.
For example:
Let's say that in an ideal world you wanted to write a consumer that looked like this (psuedocode):
boolean is_done;
int other_state;
while(!is_done)
{
//read input
//parse input
//yield input to coroutine
//update is_done and other_state;
}
we need to abstract the local variable like is_doneand other_state and we need to abstract the while loop itself because our yield like operation is not going to be using the stack. So let's create a while loop abstraction and associated classes:
enum WhileState {BREAK, CONTINUE, YIELD}
abstract class WhileLoop<T>
{
private boolean is_done;
public boolean isDone() { return is_done;}
private T rval;
public T getReturnValue() {return rval;}
protected void setReturnValue(T val)
{
rval = val;
}
public T loop()
{
while(true)
{
WhileState state = execute();
if(state == WhileState.YIELD)
return getReturnValue();
else if(state == WhileState.BREAK)
{
is_done = true;
return null;
}
}
}
protected abstract WhileState execute();
}
The Basic trick here is to move local variables to be class variables and turn scope blocks into classes which gives us the ability to 're-enter' our 'loop' after yielding our return value.
Now to implement our producer
public class SampleProducer : CoroutineProducer<Object>
{
private WhileLoop<Object> loop;//our control structures become state!!
public SampleProducer()
{
loop = new WhileLoop()
{
private int other_state;//our local variables become state of the control structure
protected WhileState execute()
{
//this implements a single iteration of the loop
if(is_done) return WhileState.BREAK;
//read input
//parse input
Object calcluated_value = ...;
//update is_done, figure out if we want to continue
setReturnValue(calculated_value);
return WhileState.YIELD;
}
};
}
public Object Produce()
{
Object val = loop.loop();
return val;
}
public boolean isDone()
{
//we are done when the loop has exited
return loop.isDone();
}
}
Similar tricks could be done for other basic control flow structures. You would ideally build up a library of these helper classes and then use them to implement these simple interfaces which would ultimately give you the semantics of co-routines. I'm sure everything I've written here can be generalized and expanded upon greatly.
I'd suggest to look at Kotlin coroutines on JVM. It falls into a different category, though. There is no byte-code manipulation involved and it works on Android, too. However, you will have to write your coroutines in Kotlin. The upside is that Kotlin is designed for interoperability with Java in mind, so you can still continue to use all your Java libraries and freely combine Kotlin and Java code in the same project, even putting them side-by-side in the same directories and packages.
This Guide to kotlinx.coroutines provides many more examples, while the coroutines design document explains all the motivation, use-cases and implementation details.
Kotlin uses the following approach for co-routines
(from https://kotlinlang.org/docs/reference/coroutines.html):
Coroutines are completely implemented through a compilation technique (no support from the VM or OS side is required), and suspension works through code transformation. Basically, every suspending function (optimizations may apply, but we'll not go into this here) is transformed to a state machine where states correspond to suspending calls. Right before a suspension, the next state is stored in a field of a compiler-generated class along with relevant local variables, etc. Upon resumption of that coroutine, local variables are restored and the state machine proceeds from the state right after suspension.
A suspended coroutine can be stored and passed around as an object that keeps its suspended state and locals. The type of such objects is Continuation, and the overall code transformation described here corresponds to the classical Continuation-passing style. Consequently, suspending functions take an extra parameter of type Continuation under the hood.
Check out the design document at https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md
I just came across this question and just want to mention that i think it might be possible to implement coroutines or generators in a similar way C# does. That said i don't actually use Java but the CIL has quite similar limitations as the JVM has.
The yield statement in C# is a pure language feature and is not part of the CIL bytecode. The C# compiler just creates a hidden private class for each generator function. If you use the yield statement in a function it has to return an IEnumerator or an IEnumerable. The compiler "packs" your code into a statemachine-like class.
The C# compiler might use some "goto's" in the generated code to make the conversion into a statemachine easier. I don't know the capabilities of Java bytecode and if there's something like a plain unconditional jump, but at "assembly level" it's usually possible.
As already mentioned this feature has to be implemented in the compiler. Because i have only little knowledge about Java and it's compiler i can't tell if it's possible to alter / extend the compiler, maybe with a "preprocessor" or something.
Personally i love coroutines. As a Unity games developer i use them quite often. Because i play alot of Minecraft with ComputerCraft i was curious why coroutines in Lua (LuaJ) are implemented with threads.
There is also Quasar for Java and Project Loom at Oracle where extensions are made to the JVM for fibers and continuations. Here is a presentation of Loom on Youtoube. There are several more. Easy to find with a little searching.
Project Loom: https://jdk.java.net/loom/ introduce Continuations to Java.
An example:
static final ContinuationScope scope=new ContinuationScope("TST");
public static void main(String[] args) {
example1();
}
// *********************************************************************
// *** EXAMPLE 1: Co-routine with three active phases:
// *********************************************************************
public static void example1() {
Continuation coroutine=new Continuation(scope,new Runnable() {
public void run() {
System.out.println("Part 1 - Statements");
Continuation.yield(scope); // DETACH 1
System.out.println("Part 2 - Statements");
Continuation.yield(scope); // DETACH 2
System.out.println("Part 3 - Statements");
}});
coroutine.run(); // Vil utføre Part 1.
System.out.println("Returns here after first DETACH(Yield)");
coroutine.run(); // Vil utføre Part 2.
System.out.println("Returns here after second DETACH(Yield)");
coroutine.run(); // Vil utføre Part 3.
System.out.println("Returns here after 'FINAL END'");
System.out.println("Next line should be: IllegalStateException: Continuation terminated");
coroutine.run(); // IllegalStateException: Continuation terminated
}
I have a Coroutine class that I use in Java. It is based on threads and using threads has the advantage of allowing parallel operation, which on multicore machines can be an advantage. Therefore you might want to consider a thread based approach.
There's an another choice is here for Java6+
A pythonic coroutine implementation:
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
class CorRunRAII {
private final List<WeakReference<? extends CorRun>> resources = new ArrayList<>();
public CorRunRAII add(CorRun resource) {
if (resource == null) {
return this;
}
resources.add(new WeakReference<>(resource));
return this;
}
public CorRunRAII addAll(List<? extends CorRun> arrayList) {
if (arrayList == null) {
return this;
}
for (CorRun corRun : arrayList) {
add(corRun);
}
return this;
}
#Override
protected void finalize() throws Throwable {
super.finalize();
for (WeakReference<? extends CorRun> corRunWeakReference : resources) {
CorRun corRun = corRunWeakReference.get();
if (corRun != null) {
corRun.stop();
}
}
}
}
class CorRunYieldReturn<ReceiveType, YieldReturnType> {
public final AtomicReference<ReceiveType> receiveValue;
public final LinkedBlockingDeque<AtomicReference<YieldReturnType>> yieldReturnValue;
CorRunYieldReturn(AtomicReference<ReceiveType> receiveValue, LinkedBlockingDeque<AtomicReference<YieldReturnType>> yieldReturnValue) {
this.receiveValue = receiveValue;
this.yieldReturnValue = yieldReturnValue;
}
}
interface CorRun<ReceiveType, YieldReturnType> extends Runnable, Callable<YieldReturnType> {
boolean start();
void stop();
void stop(final Throwable throwable);
boolean isStarted();
boolean isEnded();
Throwable getError();
ReceiveType getReceiveValue();
void setResultForOuter(YieldReturnType resultForOuter);
YieldReturnType getResultForOuter();
YieldReturnType receive(ReceiveType value);
ReceiveType yield();
ReceiveType yield(YieldReturnType value);
<TargetReceiveType, TargetYieldReturnType> TargetYieldReturnType yieldFrom(final CorRun<TargetReceiveType, TargetYieldReturnType> another);
<TargetReceiveType, TargetYieldReturnType> TargetYieldReturnType yieldFrom(final CorRun<TargetReceiveType, TargetYieldReturnType> another, final TargetReceiveType value);
}
abstract class CorRunSync<ReceiveType, YieldReturnType> implements CorRun<ReceiveType, YieldReturnType> {
private ReceiveType receiveValue;
public final List<WeakReference<CorRun>> potentialChildrenCoroutineList = new ArrayList<>();
// Outside
private AtomicBoolean isStarted = new AtomicBoolean(false);
private AtomicBoolean isEnded = new AtomicBoolean(false);
private Throwable error;
private YieldReturnType resultForOuter;
#Override
public boolean start() {
boolean isStarted = this.isStarted.getAndSet(true);
if ((! isStarted)
&& (! isEnded())) {
receive(null);
}
return isStarted;
}
#Override
public void stop() {
stop(null);
}
#Override
public void stop(Throwable throwable) {
isEnded.set(true);
if (throwable != null) {
error = throwable;
}
for (WeakReference<CorRun> weakReference : potentialChildrenCoroutineList) {
CorRun child = weakReference.get();
if (child != null) {
child.stop();
}
}
}
#Override
public boolean isStarted() {
return isStarted.get();
}
#Override
public boolean isEnded() {
return isEnded.get();
}
#Override
public Throwable getError() {
return error;
}
#Override
public ReceiveType getReceiveValue() {
return receiveValue;
}
#Override
public void setResultForOuter(YieldReturnType resultForOuter) {
this.resultForOuter = resultForOuter;
}
#Override
public YieldReturnType getResultForOuter() {
return resultForOuter;
}
#Override
public synchronized YieldReturnType receive(ReceiveType value) {
receiveValue = value;
run();
return getResultForOuter();
}
#Override
public ReceiveType yield() {
return yield(null);
}
#Override
public ReceiveType yield(YieldReturnType value) {
resultForOuter = value;
return receiveValue;
}
#Override
public <TargetReceiveType, TargetYieldReturnType> TargetYieldReturnType yieldFrom(CorRun<TargetReceiveType, TargetYieldReturnType> another) {
return yieldFrom(another, null);
}
#Override
public <TargetReceiveType, TargetYieldReturnType> TargetYieldReturnType yieldFrom(CorRun<TargetReceiveType, TargetYieldReturnType> another, TargetReceiveType value) {
if (another == null || another.isEnded()) {
throw new RuntimeException("Call null or isEnded coroutine");
}
potentialChildrenCoroutineList.add(new WeakReference<CorRun>(another));
synchronized (another) {
boolean isStarted = another.start();
boolean isJustStarting = ! isStarted;
if (isJustStarting && another instanceof CorRunSync) {
return another.getResultForOuter();
}
return another.receive(value);
}
}
#Override
public void run() {
try {
this.call();
}
catch (Exception e) {
e.printStackTrace();
stop(e);
return;
}
}
}
abstract class CorRunThread<ReceiveType, YieldReturnType> implements CorRun<ReceiveType, YieldReturnType> {
private final ExecutorService childExecutorService = newExecutorService();
private ExecutorService executingOnExecutorService;
private static final CorRunYieldReturn DUMMY_COR_RUN_YIELD_RETURN = new CorRunYieldReturn(new AtomicReference<>(null), new LinkedBlockingDeque<AtomicReference>());
private final CorRun<ReceiveType, YieldReturnType> self;
public final List<WeakReference<CorRun>> potentialChildrenCoroutineList;
private CorRunYieldReturn<ReceiveType, YieldReturnType> lastCorRunYieldReturn;
private final LinkedBlockingDeque<CorRunYieldReturn<ReceiveType, YieldReturnType>> receiveQueue;
// Outside
private AtomicBoolean isStarted = new AtomicBoolean(false);
private AtomicBoolean isEnded = new AtomicBoolean(false);
private Future<YieldReturnType> future;
private Throwable error;
private final AtomicReference<YieldReturnType> resultForOuter = new AtomicReference<>();
CorRunThread() {
executingOnExecutorService = childExecutorService;
receiveQueue = new LinkedBlockingDeque<>();
potentialChildrenCoroutineList = new ArrayList<>();
self = this;
}
#Override
public void run() {
try {
self.call();
}
catch (Exception e) {
stop(e);
return;
}
stop();
}
#Override
public abstract YieldReturnType call();
#Override
public boolean start() {
return start(childExecutorService);
}
protected boolean start(ExecutorService executorService) {
boolean isStarted = this.isStarted.getAndSet(true);
if (!isStarted) {
executingOnExecutorService = executorService;
future = (Future<YieldReturnType>) executingOnExecutorService.submit((Runnable) self);
}
return isStarted;
}
#Override
public void stop() {
stop(null);
}
#Override
public void stop(final Throwable throwable) {
if (throwable != null) {
error = throwable;
}
isEnded.set(true);
returnYieldValue(null);
// Do this for making sure the coroutine has checked isEnd() after getting a dummy value
receiveQueue.offer(DUMMY_COR_RUN_YIELD_RETURN);
for (WeakReference<CorRun> weakReference : potentialChildrenCoroutineList) {
CorRun child = weakReference.get();
if (child != null) {
if (child instanceof CorRunThread) {
((CorRunThread)child).tryStop(childExecutorService);
}
}
}
childExecutorService.shutdownNow();
}
protected void tryStop(ExecutorService executorService) {
if (this.executingOnExecutorService == executorService) {
stop();
}
}
#Override
public boolean isEnded() {
return isEnded.get() || (
future != null && (future.isCancelled() || future.isDone())
);
}
#Override
public boolean isStarted() {
return isStarted.get();
}
public Future<YieldReturnType> getFuture() {
return future;
}
#Override
public Throwable getError() {
return error;
}
#Override
public void setResultForOuter(YieldReturnType resultForOuter) {
this.resultForOuter.set(resultForOuter);
}
#Override
public YieldReturnType getResultForOuter() {
return this.resultForOuter.get();
}
#Override
public YieldReturnType receive(ReceiveType value) {
LinkedBlockingDeque<AtomicReference<YieldReturnType>> yieldReturnValue = new LinkedBlockingDeque<>();
offerReceiveValue(value, yieldReturnValue);
try {
AtomicReference<YieldReturnType> takeValue = yieldReturnValue.take();
return takeValue == null ? null : takeValue.get();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
public ReceiveType yield() {
return yield(null);
}
#Override
public ReceiveType yield(final YieldReturnType value) {
returnYieldValue(value);
return getReceiveValue();
}
#Override
public <TargetReceiveType, TargetYieldReturnType> TargetYieldReturnType yieldFrom(final CorRun<TargetReceiveType, TargetYieldReturnType> another) {
return yieldFrom(another, null);
}
#Override
public <TargetReceiveType, TargetYieldReturnType> TargetYieldReturnType yieldFrom(final CorRun<TargetReceiveType, TargetYieldReturnType> another, final TargetReceiveType value) {
if (another == null || another.isEnded()) {
throw new RuntimeException("Call null or isEnded coroutine");
}
boolean isStarted = false;
potentialChildrenCoroutineList.add(new WeakReference<CorRun>(another));
synchronized (another) {
if (another instanceof CorRunThread) {
isStarted = ((CorRunThread)another).start(childExecutorService);
}
else {
isStarted = another.start();
}
boolean isJustStarting = ! isStarted;
if (isJustStarting && another instanceof CorRunSync) {
return another.getResultForOuter();
}
TargetYieldReturnType send = another.receive(value);
return send;
}
}
#Override
public ReceiveType getReceiveValue() {
setLastCorRunYieldReturn(takeLastCorRunYieldReturn());
return lastCorRunYieldReturn.receiveValue.get();
}
protected void returnYieldValue(final YieldReturnType value) {
CorRunYieldReturn<ReceiveType, YieldReturnType> corRunYieldReturn = lastCorRunYieldReturn;
if (corRunYieldReturn != null) {
corRunYieldReturn.yieldReturnValue.offer(new AtomicReference<>(value));
}
}
protected void offerReceiveValue(final ReceiveType value, LinkedBlockingDeque<AtomicReference<YieldReturnType>> yieldReturnValue) {
receiveQueue.offer(new CorRunYieldReturn(new AtomicReference<>(value), yieldReturnValue));
}
protected CorRunYieldReturn<ReceiveType, YieldReturnType> takeLastCorRunYieldReturn() {
try {
return receiveQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
protected void setLastCorRunYieldReturn(CorRunYieldReturn<ReceiveType,YieldReturnType> lastCorRunYieldReturn) {
this.lastCorRunYieldReturn = lastCorRunYieldReturn;
}
protected ExecutorService newExecutorService() {
return Executors.newCachedThreadPool(getThreadFactory());
}
protected ThreadFactory getThreadFactory() {
return new ThreadFactory() {
#Override
public Thread newThread(final Runnable runnable) {
Thread thread = new Thread(runnable);
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable throwable) {
throwable.printStackTrace();
if (runnable instanceof CorRun) {
CorRun self = (CorRun) runnable;
self.stop(throwable);
thread.interrupt();
}
}
});
return thread;
}
};
}
}
Now you can use pythonic coroutines in this way
(e.g. fibonacci numbers)
Thread Version:
class Fib extends CorRunThread<Integer, Integer> {
#Override
public Integer call() {
Integer times = getReceiveValue();
do {
int a = 1, b = 1;
for (int i = 0; times != null && i < times; i++) {
int temp = a + b;
a = b;
b = temp;
}
// A pythonic "yield", i.e., it returns `a` to the caller and waits `times` value from the next caller
times = yield(a);
} while (! isEnded());
setResultForOuter(Integer.MAX_VALUE);
return getResultForOuter();
}
}
class MainRun extends CorRunThread<String, String> {
#Override
public String call() {
// The fib coroutine would be recycled by its parent
// (no requirement to call its start() and stop() manually)
// Otherwise, if you want to share its instance and start/stop it manually,
// please start it before being called by yieldFrom() and stop it in the end.
Fib fib = new Fib();
String result = "";
Integer current;
int times = 10;
for (int i = 0; i < times; i++) {
// A pythonic "yield from", i.e., it calls fib with `i` parameter and waits for returned value as `current`
current = yieldFrom(fib, i);
if (fib.getError() != null) {
throw new RuntimeException(fib.getError());
}
if (current == null) {
continue;
}
if (i > 0) {
result += ",";
}
result += current;
}
setResultForOuter(result);
return result;
}
}
Sync(non-thread) version:
class Fib extends CorRunSync<Integer, Integer> {
#Override
public Integer call() {
Integer times = getReceiveValue();
int a = 1, b = 1;
for (int i = 0; times != null && i < times; i++) {
int temp = a + b;
a = b;
b = temp;
}
yield(a);
return getResultForOuter();
}
}
class MainRun extends CorRunSync<String, String> {
#Override
public String call() {
CorRun<Integer, Integer> fib = null;
try {
fib = new Fib();
} catch (Exception e) {
e.printStackTrace();
}
String result = "";
Integer current;
int times = 10;
for (int i = 0; i < times; i++) {
current = yieldFrom(fib, i);
if (fib.getError() != null) {
throw new RuntimeException(fib.getError());
}
if (current == null) {
continue;
}
if (i > 0) {
result += ",";
}
result += current;
}
stop();
setResultForOuter(result);
if (Utils.isEmpty(result)) {
throw new RuntimeException("Error");
}
return result;
}
}
Execution(Both versions will work):
// Run the entry coroutine
MainRun mainRun = new MainRun();
mainRun.start();
// Wait for mainRun ending for 5 seconds
long startTimestamp = System.currentTimeMillis();
while(!mainRun.isEnded()) {
if (System.currentTimeMillis() - startTimestamp > TimeUnit.SECONDS.toMillis(5)) {
throw new RuntimeException("Wait too much time");
}
}
// The result should be "1,1,2,3,5,8,13,21,34,55"
System.out.println(mainRun.getResultForOuter());
Instead of using any other method just create a wrapper class for java
/**
* This class will be used run java code in the kotlin coroutines
* #author : prustyA : 17/06/2022
*/
class CoroutineJava {
//Scope
private val context: CoroutineContext = Dispatchers.IO
private val scope = CoroutineScope(context)
/**
* This method will be used to return current coroutine context
* #author : prustyA : 17/06/2022
*/
fun getContext() = context
/**
* This method will be used to start executing the method block
* #author : prustyA : 17/06/2022
*/
fun launch(block: () -> Unit) {
scope.launch { block() }
}
/**
* This method will be used to change the context and run the block
* #author : prustyA : 17/06/2022
*/
fun launchWithContext(context: CoroutineContext,block: () -> Unit) {
scope.launch {
withContext(context) { block() }
}
}
}