Содержание
Несколько примеров Java 8 для параллельного выполнения потоков.
1. BaseStream.parallel ()
Простой параллельный пример для печати от 1 до 10.
ParallelExample1.java
package com.csharpcoderr.java8;
import java.util.stream.IntStream;
public class ParallelExample1 {
public static void main(String[] args) {
System.out.println("Normal...");
IntStream range = IntStream.rangeClosed(1, 10);
range.forEach(System.out::println);
System.out.println("Parallel...");
IntStream range2 = IntStream.rangeClosed(1, 10);
range2.parallel().forEach(System.out::println);
}
}
Выход
Normal...
1
2
3
4
5
6
7
8
9
10
Parallel...
7
6
8
9
10
1
4
5
3
2
2. Collection.parallelStream ()
Еще один простой параллельный пример для печати a
в z
, Для сбора мы можем использовать parallelStream()
,
ParallelExample2.java
package com.csharpcoderr.java8;
import java.util.ArrayList;
import java.util.List;
public class ParallelExample2 {
public static void main(String[] args) {
System.out.println("Normal...");
List alpha = getData();
alpha.stream().forEach(System.out::println);
System.out.println("Parallel...");
List alpha2 = getData();
alpha2.parallelStream().forEach(System.out::println);
}
private static List getData() {
List alpha = new ArrayList<>();
int n = 97; // 97 = a, 122 = z
while (n <= 122) {
char c = (char) n;
alpha.add(String.valueOf(c));
n++;
}
return alpha;
}
}
Выход
Normal...
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
Parallel...
q
s
r
o
x
h
l
p
d
i
g
t
u
n
z
v
j
k
w
f
m
c
a
e
b
y
3. Поток работает в параллельном режиме?
3.1 Мы можем проверить это с isParallel()
ParallelExample3a.java
package com.csharpcoderr.java8;
import java.util.stream.IntStream;
public class ParallelExample3a {
public static void main(String[] args) {
System.out.println("Normal...");
IntStream range = IntStream.rangeClosed(1, 10);
System.out.println(range.isParallel()); // ложный
range.forEach(System.out::println);
System.out.println("Parallel...");
IntStream range2 = IntStream.rangeClosed(1, 10);
IntStream range2Parallel = range2.parallel();
System.out.println(range2Parallel.isParallel()); // правда
range2Parallel.forEach(System.out::println);
}
}
3.2 Или напечатайте текущее имя потока следующим образом:
ParallelExample3b.java
package com.csharpcoderr.java8;
import java.util.stream.IntStream;
public class ParallelExample3b {
public static void main(String[] args) {
System.out.println("Normal...");
IntStream range = IntStream.rangeClosed(1, 10);
range.forEach(x -> {
System.out.println("Thread : " + Thread.currentThread().getName() + ", value: " + x);
});
System.out.println("Parallel...");
IntStream range2 = IntStream.rangeClosed(1, 10);
range2.parallel().forEach(x -> {
System.out.println("Thread : " + Thread.currentThread().getName() + ", value: " + x);
});
}
}
Выход
Normal...
Thread : main, value: 1
Thread : main, value: 2
Thread : main, value: 3
Thread : main, value: 4
Thread : main, value: 5
Thread : main, value: 6
Thread : main, value: 7
Thread : main, value: 8
Thread : main, value: 9
Thread : main, value: 10
Parallel...
Thread : main, value: 7
Thread : main, value: 6
Thread : ForkJoinPool.commonPool-worker-5, value: 3
Thread : ForkJoinPool.commonPool-worker-7, value: 8
Thread : ForkJoinPool.commonPool-worker-5, value: 5
Thread : ForkJoinPool.commonPool-worker-5, value: 4
Thread : ForkJoinPool.commonPool-worker-3, value: 9
Thread : ForkJoinPool.commonPool-worker-5, value: 1
Thread : ForkJoinPool.commonPool-worker-7, value: 2
Thread : ForkJoinPool.commonPool-worker-9, value: 10
PS По умолчанию параллельные потоки используют `ForkJoinPool`
4. Расчет
4.1 Java 8 потоков для печати всех простых чисел до 1 миллиона:
ParallelExample4.java
package com.csharpcoderr.java8;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class ParallelExample4 {
public static void main(String[] args) {
long count = Stream.iterate(0, n -> n + 1)
.limit(1_000_000)
// .rallel () с этими 23 с, без этого 1 м 10 с
.filter(ParallelExample4::isPrime)
.peek(x -> System.out.format("%st", x))
.count();
System.out.println("nTotal: " + count);
}
public static boolean isPrime(int number) {
if (number <= 1) return false;
return !IntStream.rangeClosed(2, number / 2).anyMatch(i -> number % i == 0);
}
}
Результат:
- Для обычных потоков это занимает 1 минуту 10 секунд.
- Для параллельных потоков это занимает 23 секунды.
PS Протестировано с i7-7700, 16G RAM, Windows 10
4.2 Еще один пример параллельного потока для определения среднего возраста списка сотрудников.
List employees = obj.generateEmployee(10000);
double age = employees
.parallelStream()
.mapToInt(Employee::getAge)
.average()
.getAsDouble();
System.out.println("Average age: " + age);
5. Тематическое исследование
5.1 Параллельные потоки для повышения производительности трудоемких задач сохранения файлов.
Этот код Java сгенерирует 10000 случайных сотрудников и сохранит в 10000 файлов, каждый сотрудник сохранит в файл.
- Для обычного потока это занимает 27-29 секунд.
- Для параллельного потока это занимает 7-8 секунд.
PS Протестировано с i7-7700, 16G RAM, Windows 10
ParallelExample5.java
package com.csharpcoderr.java8;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ParallelExample5 {
private static final String DIR = System.getProperty("user.dir") + "/test/";
public static void main(String[] args) throws IOException {
Files.createDirectories(Paths.get(DIR));
ParallelExample5 obj = new ParallelExample5();
List employees = obj.generateEmployee(10000);
// нормальный, последовательный
//employees.stream().forEach(ParallelExample5::save); // 27-е-29-е
// параллельно
employees.parallelStream().forEach(ParallelExample5::save); // 7с-8с
}
private static void save(Employee input) {
try (FileOutputStream fos = new FileOutputStream(new File(DIR + input.getName() + ".txt"));
ObjectOutputStream obs = new ObjectOutputStream(fos)) {
obs.writeObject(input);
} catch (IOException e) {
e.printStackTrace();
}
}
private List generateEmployee(int num) {
return Stream.iterate(0, n -> n + 1)
.limit(num)
.map(x -> {
return new Employee(
generateRandomName(4),
generateRandomAge(15, 100),
generateRandomSalary(900.00, 200_000.00)
);
})
.collect(Collectors.toList());
}
private String generateRandomName(int length) {
return new Random()
.ints(5, 97, 122) // 97 = a, 122 = z
.mapToObj(x -> String.valueOf((char) x))
.collect(Collectors.joining());
}
private int generateRandomAge(int min, int max) {
return new Random()
.ints(1, min, max)
.findFirst()
.getAsInt();
}
private BigDecimal generateRandomSalary(double min, double max) {
return new BigDecimal(new Random()
.doubles(1, min, max)
.findFirst()
.getAsDouble()).setScale(2, RoundingMode.HALF_UP);
}
}
Employee.java
package com.csharpcoderr.java8;
import java.io.Serializable;
import java.math.BigDecimal;
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private BigDecimal salary;
// геттеры, сеттеры и т.д ...
}
Рекомендации
- Учебные руководства Java - Параллелизм
- Примеры Java 8 Stream.iterate
- Примеры простых чисел в Java
- Что не так в Java 8, часть III: потоки и параллельные потоки
Параллельный поток Java 8 параллельных простых чисел
0.00 (0%) 0 votes