Follow along with the video below to see how to install our site as a web app on your home screen.
Anmerkung: This feature may not be available in some browsers.
Die Bezeichnung ist auch eine Frage der Definition.Virtuelle Threads sind auch Threads.
Aha, Du meinst Java, JDK, Libs und Frameworks.Die zweite Problematik aus meiner Sicht ist: Kenne Dein System!
Platform thread ist der richtige Name.Die normalen Java-Threads haben ihre Wiederspiegelung im Betriebssystem.
Guck mal
Continuations: The magic behind virtual threads in Java by Balkrishna Rawool
Wie wäre es, wenn wir im Java Bereich einfach die Begriffe verwenden würden, die von den Verantwortlichen gewählt wurden in den Spezifikationen und in der JavaDoc?Die Bezeichnung ist auch eine Frage der Definition.
Du bist echt lustig - Was habe ich den geschrieben? Schauen wir einfach einmal nach:Platform thread ist der richtige Name.
Eine Instanz von Thread kann also sowohl ein "platform thread" oder ein "virtual thread" sein.
Super, da hast Du dann ja jetzt über Continuations auch einen Weg, da Dir ja die Wege über Streams, Iteratoren und Supplier nicht gefallen. Aber ist doch super, dass dies als Möglichkeiten auch alle genannt wurden im Video.Ich bin überrascht, ab Minute 18 spricht der Vortragende über Generators.
Das Problem ist, dass der Iterator Anweisungen ausführt, nachdem der Wert abgerufen wurde.Wo ist denn da das Problem? Das mit dem ProduceEvenNumbers ist dann ein einfacher Supplier<Integer>. Das Limit upTo wandert aber in den Stream (so man Streams verwenden möchte) was auch Sinn macht, denn der Generator ist ein generisches erzeugen der geraden Zahlen und das Limitieren ist eine Frage der Nutzung.
package de.kneitzel;
import java.util.Iterator;
import java.util.function.Consumer;
public class Generator<T> implements Iterator<T> {
private final Source source;
private final Object lock = new Object();
private valitile boolean completed = false;
public Generator(Consumer<Source> consumer) {
source = new Source();
Thread.ofVirtual().start(() -> {
consumer.accept(source);
synchronized (lock) {
completed = true;
lock.notifyAll();
}
});
}
public boolean hasNext() {
synchronized (lock) {
return !completed || source.value != null;
}
}
public T next() {
synchronized (lock) {
while (source.value == null && !completed) {
try {
lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
T result = source.value;
source.value = null;
lock.notify();
return result;
}
}
public class Source {
private T value;
public void yield(T t) {
synchronized (lock) {
while (value != null) {
try {
lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
value = t;
lock.notify();
}
}
}
public static void main(String[] args) throws Exception {
var generator = new Generator<String>(source -> {
source.yield("A");
source.yield("B");
source.yield("C");
});
while (generator.hasNext()) {
System.out.println(generator.next());
}
}
}
package de.kneitzel;
import java.util.Iterator;
import java.util.function.Consumer;
public class Generator<T> implements AutoCloseable, Iterator<T> {
private final Source source;
private final Thread thread;
private final Object lock = new Object();
private volatile boolean completed = false;
public Generator(Consumer<Source> consumer) {
source = new Source();
thread = Thread.ofVirtual().start(() -> {
consumer.accept(source);
synchronized (lock) {
completed = true;
lock.notifyAll();
}
});
}
public boolean hasNext() {
synchronized (lock) {
return !completed || source.value != null;
}
}
public T next() {
synchronized (lock) {
while (source.value == null && !completed) {
try {
lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
T result = source.value;
source.value = null;
lock.notify();
return result;
}
}
@Override
public void close() throws Exception {
if (thread != null) {
thread.interrupt();
}
}
public class Source {
private T value;
public void yiald(T t) {
synchronized (lock) {
while (value != null) {
try {
lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
value = t;
lock.notify();
}
}
}
public static void main(String[] args) throws Exception {
var generator = new Generator<String>(source -> {
source.yiald("A");
source.yiald("B");
source.yiald("C");
});
if (generator.hasNext()) {
System.out.println(generator.next());
}
generator.close();
}
}
package de.kneitzel;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.function.Consumer;
public class Generator<T> {
private final BlockingQueue<T> queue = new ArrayBlockingQueue<>(1);
private volatile boolean completed = false;
public Generator(Consumer<Source> consumer) {
Thread.ofVirtual().start(() -> {
try {
consumer.accept(new Source());
} finally {
completed = true;
}
});
}
public boolean hasNext() {
return !completed || !queue.isEmpty();
}
public T next() {
try {
T result = queue.take();
if (result == null) {
completed = true;
}
return result;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public class Source {
public void yield(T t) {
try {
queue.put(t);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
var generator = new Generator<String>(source -> {
source.yield("A");
source.yield("B");
source.yield("C");
});
while (generator.hasNext()) {
System.out.println(generator.next());
}
}
}
Sehr gut.Ok, so langsam habe ich dann jetzt die Problematik so langsam verstanden.
Ein Beispiel wäre das durchlaufen eines binären Baumes in sortierte Reihenfolge.Dann gibt es tatsächlich Situationen, bei denen man einen komplexen Generator hat, bei dem dies so nicht abbildbar ist. Mir fällt da kein gutes Beispiel ein
private volatile boolean completed = false;package de.kneitzel;
import java.util.Iterator;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
public class Generator<T> implements AutoCloseable, Iterator<T> {
private final Source source;
private final Thread thread;
private final ReentrantLock lock = new ReentrantLock();
private final Condition valueAvailable = lock.newCondition();
private final Condition valueConsumed = lock.newCondition();
private volatile boolean completed = false;
public Generator(Consumer<Source> consumer) {
source = new Source();
thread = Thread.ofVirtual().start(() -> {
consumer.accept(source);
lock.lock();
try {
completed = true;
valueAvailable.signalAll();
} finally {
lock.unlock();
}
});
}
public boolean hasNext() {
lock.lock();
try {
while (!completed && source.value == null) {
valueAvailable.await();
}
return source.value != null;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
public T next() {
lock.lock();
try {
while (source.value == null && !completed) {
valueAvailable.await();
}
T result = source.value;
source.value = null;
valueConsumed.signal();
return result;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
@Override
public void close() {
if (thread != null) {
thread.interrupt();
}
}
public class Source {
private T value;
public void yiald(T t) {
lock.lock();
try {
while (value != null) {
valueConsumed.await();
}
value = t;
valueAvailable.signal();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) throws Exception {
try (var generator = new Generator<String>(source -> {
source.yiald("A");
source.yiald("B");
source.yiald("C");
})) {
while (generator.hasNext()) {
System.out.println(generator.next());
}
}
}
}