Pambuka
Kita wis ndeleng carane thread digawe ing
bagean pisanan . Ayo eling maneh.
Utas iku
Thread
ana sing mlaku
run
, mula ayo nggunakake
kompiler online tutorialspoint java lan nglakokake kode ing ngisor iki:
public class HelloWorld {
public static void main(String []args){
Runnable task = () -> {
System.out.println("Hello World");
};
new Thread(task).start();
}
}
Apa iki mung siji-sijine pilihan kanggo mbukak tugas ing thread?
java.util.concurrent.Callable
Pranyata
java.lang.Runnable duwe sedulur lanang jenenge
java.util.concurrent.Callable lan lair ing Jawa 1.5. Apa bedane? Yen kita nliti JavaDoc antarmuka iki, kita weruh manawa, ora kaya
Runnable
, antarmuka anyar nyatakake cara
call
sing ngasilake asil. Uga, kanthi standar mbuwang Exception. Sing, nyimpen kita saka perlu kanggo nulis
try-catch
pamblokiran kanggo pangecualian dicenthang. Ora ala wis, ta? Saiki kita duwe
Runnable
tugas anyar tinimbang:
Callable task = () -> {
return "Hello, World!";
};
Nanging apa sing kudu dilakoni? Napa kita butuh tugas sing mlaku ing benang sing ngasilake asil? Temenan, ing tembe ngarep-arep bakal nampa asil saka tumindak sing bakal ditindakake ing mangsa ngarep. Future in English - Future. Lan ana antarmuka kanthi jeneng sing padha:
java.util.concurrent.Future
java.util.concurrent.Future
Antarmuka
java.util.concurrent.Future njlèntrèhaké API kanggo nggarap tugas sing asile bakal dipikolehi ing mangsa ngarep: cara kanggo entuk asil, cara kanggo mriksa status. Kita
Future
kasengsem ing implementasine
java.util.concurrent.FutureTask . Yaiku
Task
, iki sing bakal dieksekusi ing
Future
. Sing uga menarik babagan implementasine iki yaiku ngetrapake lan
Runnable
. Sampeyan bisa nimbang iki jenis adaptor saka model lawas nggarap tugas ing Utas lan model anyar (anyar ing pangertèn sing katon ing java 1.5). Iki contone:
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class HelloWorld {
public static void main(String []args) throws Exception {
Callable task = () -> {
return "Hello, World!";
};
FutureTask<String> future = new FutureTask<>(task);
new Thread(future).start();
System.out.println(future.get());
}
}
Kaya sing bisa dideleng saka conto, nggunakake metode kita entuk
get
asil saka masalah
task
.
(!)Penting, yen ing wayahe asil dipikolehi nggunakake metode kasebut,
get
eksekusi dadi sinkron. Mekanisme apa sampeyan mikir bakal digunakake ing kene? Bener, ora ana blok sinkronisasi - mula kita bakal weruh
NUNGGU ing JVisualVM ora minangka
monitor
utawa
wait
, nanging minangka sing padha
park
(amarga mekanisme digunakake
LockSupport
).
Antarmuka Fungsional
Sabanjure kita bakal pirembagan bab kelas saka Java 1.8, supaya bakal migunani kanggo nggawe introduksi singkat. Ayo ndeleng kode ing ngisor iki:
Supplier<String> supplier = new Supplier<String>() {
@Override
public String get() {
return "String";
}
};
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
Function<String, Integer> converter = new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.valueOf(s);
}
};
Ana akeh kode sing ora perlu, ta? Saben kelas sing diumumake nindakake fungsi siji, nanging kanggo njlèntrèhaké, kita nggunakake sekumpulan kode tambahan sing ora perlu. Lan para pangembang Jawa uga mikir. Mulane, dheweke ngenalake sakumpulan "antarmuka fungsional" (
@FunctionalInterface
) lan mutusake yen saiki Jawa dhewe bakal "mikir" kabeh kanggo kita, kajaba sing penting:
Supplier<String> supplier = () -> "String";
Consumer<String> consumer = s -> System.out.println(s);
Function<String, Integer> converter = s -> Integer.valueOf(s);
Supplier
- panyedhiya. Ora ana paramèter, nanging ngasilake barang, yaiku, nyedhiyakake.
Consumer
- konsumen. Butuh soko minangka input (parameter s) lan nindakake soko karo, sing, nganggo soko. Ana fungsi liyane. Butuh soko minangka input (parameter
s
), nindakake soko lan ngasilake soko. Kaya sing kita deleng, generik digunakake kanthi aktif. Yen sampeyan ora yakin, sampeyan bisa ngelingi lan maca "
Teori generik ing Jawa utawa carane ngetrapake kurung ing praktik ."
CompletableFuture
Sajrone wektu, Java 1.8 ngenalake kelas anyar sing diarani
CompletableFuture
. Iku ngleksanakake antarmuka
Future
, tegese kita
task
bakal dieksekusi ing mangsa ngarep lan kita bisa nglakokake
get
lan entuk asil. Nanging dheweke uga nindakake sawetara
CompletionStage
. Saka terjemahan tujuane wis jelas: iku Tahap tartamtu saka sawetara jinis pitungan. Pambuka ringkes babagan topik kasebut bisa ditemokake ing ringkesan "
Introduction to CompletionStage and CompletableFuture ". Ayo langsung menyang titik. Ayo goleki dhaptar metode statis sing kasedhiya kanggo mbantu kita miwiti:
Ing ngisor iki pilihan kanggo nggunakake:
import java.util.concurrent.CompletableFuture;
public class App {
public static void main(String []args) throws Exception {
CompletableFuture<String> completed;
completed = CompletableFuture.completedFuture("Просто meaning");
CompletableFuture<Void> voidCompletableFuture;
voidCompletableFuture = CompletableFuture.runAsync(() -> {
System.out.println("run " + Thread.currentThread().getName());
});
CompletableFuture<String> supplier;
supplier = CompletableFuture.supplyAsync(() -> {
System.out.println("supply " + Thread.currentThread().getName());
return "Значение";
});
}
}
Yen kita mbukak kode iki, kita bakal weruh sing nggawe
CompletableFuture
kalebu miwiti kabeh chain. Mulane, nalika ana sawetara podho karo SteamAPI saka Java8, iki prabédan antarane pendekatan iki. Tuladhane:
List<String> array = Arrays.asList("one", "two");
Stream<String> stringStream = array.stream().map(value -> {
System.out.println("Executed");
return value.toUpperCase();
});
Iki minangka conto Java 8 Stream Api (sampeyan bisa maca liyane babagan kene "
Java 8 Stream API Guide ing Gambar lan Conto "). Yen sampeyan mbukak kode iki,
Executed
ora bakal ditampilake. Yaiku, nalika nggawe stream ing Jawa, stream ora langsung diwiwiti, nanging ngenteni nganti ana nilai sing dibutuhake. Nanging
CompletableFuture
wiwit chain kanggo eksekusi langsung, tanpa ngenteni kanggo takon kanggo Nilai diwilang. Aku iki penting kanggo ngerti iki. Dadi kita duwe CompletableFuture. Kepiye carane nggawe rantai lan apa sing kita duwe? Ayo elinga babagan antarmuka fungsional sing wis ditulis sadurunge.
- We duwe fungsi (
Function
) sing njupuk A lan ngasilake B. Wis cara siji - apply
(aplikasi).
- Kita duwe konsumen (
Consumer
) sing nampa A lan ora ngasilake apa-apa ( Void ). Wis mung siji cara - accept
(nampa).
- Kita duwe kode mlaku ing thread
Runnable
sing ora nampa utawa bali. Wis siji cara - run
(run).
Kapindho sing kudu dielingake yaiku
CompletalbeFuture
ing karyane nggunakake
Runnable
konsumen lan fungsi. Amarga iki, sampeyan bisa tansah eling yen sampeyan
CompletableFuture
bisa nindakake iki:
public static void main(String []args) throws Exception {
AtomicLong longValue = new AtomicLong(0);
Runnable task = () -> longValue.set(new Date().getTime());
Function<Long, Date> dateConverter = (longvalue) -> new Date(longvalue);
Consumer<Date> printer = date -> {
System.out.println(date);
System.out.flush();
};
CompletableFuture.runAsync(task)
.thenApply((v) -> longValue.get())
.thenApply(dateConverter)
.thenAccept(printer);
}
Metode
thenRun
duwe
thenApply
versi .
thenAccept
_
Async
Iki tegese tahapan kasebut bakal dieksekusi ing thread anyar. Iku bakal dijupuk saka blumbang khusus, supaya ora dingerteni ing advance apa jenis aliran bakal, anyar utawa lawas. Iku kabeh gumantung carane angel tugas. Saliyane cara kasebut, ana telung kemungkinan sing luwih menarik. Kanggo gamblang, ayo bayangake manawa kita duwe layanan tartamtu sing nampa pesen saka endi wae lan butuh wektu:
public static class NewsService {
public static String getMessage() {
try {
Thread.currentThread().sleep(3000);
return "Message";
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
}
Saiki, ayo goleki fitur liyane sing
CompletableFuture
. Kita bisa gabungke asil
CompletableFuture
karo asil liyane
CompletableFuture
:
Supplier newsSupplier = () -> NewsService.getMessage();
CompletableFuture<String> reader = CompletableFuture.supplyAsync(newsSupplier);
CompletableFuture.completedFuture("!!")
.thenCombine(reader, (a, b) -> b + a)
.thenAccept(result -> System.out.println(result))
.get();
Wigati dicathet yen kanthi standar benang bakal dadi benang daemon, supaya luwih jelas
get
, kita ngenteni asile. Lan kita ora mung bisa nggabungake (gabungan), nanging uga bali
CompletableFuture
:
CompletableFuture.completedFuture(2L)
.thenCompose((val) -> CompletableFuture.completedFuture(val + 2))
.thenAccept(result -> System.out.println(result));
Ing kene aku pengin nyathet yen kanggo ringkesan, metode kasebut digunakake
CompletableFuture.completedFuture
. Cara iki ora nggawe utas anyar, mula rantai liyane bakal dieksekusi ing benang sing padha sing diarani
completedFuture
. Ana uga cara
thenAcceptBoth
. Iku banget padha karo
accept
, nanging yen
thenAccept
nampa
consumer
, banjur
thenAcceptBoth
nampa liyane
CompletableStage
+ minangka input
BiConsumer
, sing
consumer
, kang nampa 2 sumber minangka input, ora siji. Ana kemungkinan liyane sing menarik karo tembung
Either
:
Cara iki nampa alternatif
CompletableStage
lan bakal dieksekusi ing sing
CompletableStage
dieksekusi luwih dhisik. Lan aku pengin ngrampungake review iki kanthi fitur sing luwih menarik
CompletableFuture
- penanganan kesalahan.
CompletableFuture.completedFuture(2L)
.thenApply((a) -> {
throw new IllegalStateException("error");
}).thenApply((a) -> 3L)
.thenAccept(val -> System.out.println(val));
Kode iki ora bakal nindakake apa-apa, amarga ... pangecualian bakal dibuwang lan ora bakal kelakon. Nanging yen kita uncomment
exceptionally
, banjur kita nemtokake prilaku.
CompletableFuture
Aku uga nyaranake nonton video ing ngisor iki babagan topik iki :
Ing mratelakake panemume andhap asor, video iki sawetara sing paling visual ing Internet. Iku kudu cetha saka wong-wong mau carane kabeh bisa, apa arsenal kita duwe lan apa iku kabeh perlu.
Kesimpulan
Muga-muga saiki wis jelas kepiye carane benang bisa digunakake kanggo njupuk petungan sawise diitung. Materi tambahan:
#Viacheslav
GO TO FULL VERSION