-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
{"assignment":"java-advanced-ru/sync-primitives"} | ||
{"assignment":"java-advanced-ru/asynchrony"} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.gradle/ | ||
build/ |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
test: | ||
gradle test | ||
|
||
run: | ||
gradle run |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Асинхронность | ||
|
||
Асинхронность в программировании — выполнение процесса в неблокирующем режиме, что позволяет основному потоку программы продолжить обработку. | ||
|
||
## Ссылки | ||
|
||
* [Класс CompletableFuture – представляет собой отложенный результат асинхронных вычислений](https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/util/concurrent/CompletableFuture.html) | ||
* [Класс Files – содержит статические методы для работы с файлами и директориями](https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/nio/file/Files.html) | ||
|
||
## src/main/java/exercise/App.java | ||
|
||
## Задачи | ||
|
||
* Создайте асинхронный публичный статический метод `unionFiles()`. Метод должен асинхронно читать содержимое двух файлов, объединять эту информацию и записывать её в третий файл. Метод принимает три аргумента – пути до файлов в виде строки. Первые два аргумента – пути до файлов-источников, третий – путь до итогового файла. Метод может принимать абсолютный и относительный путь до файлов. Если хотя-бы один из файлов-источников не существует, на экран должно выводиться сообщение о возникшем исключении. Если итоговый файл не существует, он должен быть создан. Метод должен возвращать `CompletableFuture<String>`. | ||
|
||
```java | ||
CompletableFuture<String> result = App.unionFiles("file1.txt", "file2.txt", "dest.txt"); | ||
``` | ||
|
||
Конечно, чтение файлов можно выполнить и синхронно. Но представьте, что у нас сложные задачи, которые выполняются длительное время, например конвертация видеофайла. В этом случае, асинхронный, неблокирующий запуск задач позволит нам получить выигрыш. | ||
|
||
* В методе `main()`, используя асинхронный метод `unionFiles()`, прочитайте информацию из двух файлов *src/main/resources/file1.txt* и *src/main/resources/file2.txt* и запишите её в третий файл в этой же директории. Имя файла выберите на своё усмотрение. | ||
|
||
* Запустите программу при помощи команды `make run`. Убедитесь, что целевой файл создался и он содержит информацию из двух источников. | ||
|
||
### Самостоятельная работа | ||
|
||
* В классе `App` создайте асинхронный публичный статический метод `getDirectorySize()`, который считает размеры переданной директории не включая поддиректории. Размер директории складывается из размера всех файлов в директории. Метод должен вернуть `CompletableFuture<Long>`. | ||
|
||
```java | ||
CompletableFuture<Long> size = App.getDirectorySize("dir/subdir"); | ||
``` | ||
|
||
* Напишите тесты, проверяющие работу этого метода. | ||
|
||
### Подсказки | ||
|
||
* Для обработки возникших в асинхронном коде исключений можно использовать метод [exceptionally()](https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/util/concurrent/CompletableFuture.html#exceptionally(java.util.function.Function)) | ||
|
||
* Для того, чтобы независимо друг от друга выполнить две задачи, и затем сделать что-то после их выполнения, можно использовать метод [thenCombine()](https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/util/concurrent/CompletableFuture.html#thenCombine(java.util.concurrent.CompletionStage,java.util.function.BiFunction)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
plugins { | ||
id 'application' | ||
id 'com.adarshr.test-logger' version '2.1.1' | ||
} | ||
|
||
repositories { | ||
mavenCentral() | ||
} | ||
|
||
dependencies { | ||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.0-M1' | ||
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.0-M1' | ||
testImplementation 'org.assertj:assertj-core:3.19.0' | ||
testImplementation 'com.github.stefanbirkner:system-lambda:1.2.0' | ||
} | ||
|
||
application { | ||
mainClass = 'exercise.App' | ||
} | ||
|
||
test { | ||
useJUnitPlatform() | ||
} | ||
|
||
testlogger { | ||
showStandardStreams = true | ||
} | ||
|
||
tasks.withType(JavaCompile) { | ||
options.encoding = "UTF-8" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
class Example { | ||
public static void main(String[] args) { | ||
|
||
// Если нам нужно просто асинхронно выполнить задачу и не нужно ничего возвращать | ||
|
||
// В виде лямбды передаём объект Runnable | ||
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> { | ||
// Задержка имитирует длительно выполняющуюся задачу | ||
try { | ||
TimeUnit.SECONDS.sleep(1); | ||
} catch (InterruptedException e) { | ||
throw new IllegalStateException(e); | ||
} | ||
System.out.println("Run in separate thread"); | ||
}); | ||
|
||
// Ожидаем окончания работы задачи | ||
future1.get(); | ||
|
||
|
||
// Асинхронный запуск задачи и возврат результата работы | ||
|
||
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> { | ||
// Задержка имитирует длительно выполняющуюся задачу | ||
try { | ||
TimeUnit.SECONDS.sleep(1); | ||
} catch (InterruptedException e) { | ||
throw new IllegalStateException(e); | ||
} | ||
return "Result of async computation"; | ||
}); | ||
|
||
// Ожидаем окончания работы задачи и получаем результат | ||
String result = future2.get(); // "Result of async computation" | ||
|
||
// Комбинирование двух CompletableFuture | ||
|
||
// Если одна задача не зависит от другой | ||
// Нужно выполнить две задачи независимо одна от другой и выполнить третью, | ||
// когда предыдущее будут завершены | ||
|
||
|
||
// Задачи выполняются независимо друг от друга | ||
System.out.println("Retrieving weight"); | ||
CompletableFuture<Integer> futureWeight = CompletableFuture.supplyAsync(() -> { | ||
|
||
try { | ||
TimeUnit.SECONDS.sleep(1); | ||
} catch (Exception e) { | ||
throw new IllegalStateException(e); | ||
} | ||
return 100; | ||
}); | ||
|
||
System.out.println("Retrieving volume"); | ||
CompletableFuture<Integer> futureVolume = CompletableFuture.supplyAsync(() -> { | ||
|
||
try { | ||
TimeUnit.SECONDS.sleep(1); | ||
} catch (Exception e) { | ||
throw new IllegalStateException(e); | ||
} | ||
return 2; | ||
}); | ||
|
||
// выполняется после завершения первых двух | ||
System.out.println("Calculate density"); | ||
CompletableFuture<Integer> futureDensity = futureWeight.thenCombine(futureVolume, (weight, volume) -> { | ||
Integer density = weight / volume; | ||
return density; | ||
|
||
// Обработка исключений | ||
// Если при работе задач возникли исключения | ||
// их можно обработать в методе exceptionally | ||
}).exceptionally(ex -> { | ||
System.out.println("Oops! We have an exception - " + ex.getMessage()); | ||
return null; | ||
}); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
distributionBase=GRADLE_USER_HOME | ||
distributionPath=wrapper/dists | ||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip | ||
networkTimeout=10000 | ||
validateDistributionUrl=true | ||
zipStoreBase=GRADLE_USER_HOME | ||
zipStorePath=wrapper/dists |