Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 64 additions & 3 deletions core-java-modules/core-java-concurrency-advanced-7/pom.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>core-java-concurrency-advanced-7</artifactId>
<packaging>jar</packaging>
Expand All @@ -20,10 +19,72 @@
<version>${awaitility.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${jmh.core.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.core.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source.version}</source>
<target>${maven.compiler.target.version}</target>
<debug>false</debug>
<compilerArgs>
<arg>--enable-preview</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.core.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>--enable-preview</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
<configuration>
<finalName>benchmarks</finalName>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.openjdk.jmh.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

<properties>
<awaitility.version>1.7.0</awaitility.version>
<maven.compiler.source.version>21</maven.compiler.source.version>
<maven.compiler.target.version>21</maven.compiler.target.version>
<jmh.core.version>1.37</jmh.core.version>
</properties>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.baeldung.virtualthread.classinit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HeavyClass {

private static final Logger LOGGER = LoggerFactory.getLogger(HeavyClass.class);

static {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}

LOGGER.info("static initialization done");
}

{
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}

LOGGER.info("initialization done");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.baeldung.virtualthread.classloader;

import java.io.IOException;
import java.nio.file.Path;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class CustomClassLoader extends ClassLoader {

private static final Logger LOGGER = LoggerFactory.getLogger(CustomClassLoader.class);
private final Path classDir;

public CustomClassLoader(Path classDir) {
super(ClassLoader.getSystemClassLoader());
this.classDir = classDir;
}

@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
LOGGER.info("Load class for {}", name);

Class<?> clazz = findLoadedClass(name);

if (clazz == null) {
try {
clazz = findClass(name);
} catch (ClassNotFoundException ex) {
clazz = super.loadClass(name, resolve);
}
}

if (resolve) {
resolveClass(clazz);
}

return clazz;
}

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
LOGGER.info("Finding class for {}", name);

try {
Path file = classDir.resolve(name.replace('.', '/') + ".class");
byte[] bytes = java.nio.file.Files.readAllBytes(file);
Thread.sleep(100);

return defineClass(name, bytes, 0, bytes.length);
} catch (InterruptedException | IOException ex) {
LOGGER.error("Error while finding class file {}", ex.getMessage());
throw new ClassNotFoundException(ex.getMessage(), ex);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.baeldung.virtualthread.classloader;

public class MyClass {
public MyClass() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.baeldung.virtualthread.foreignfunction;

import static java.lang.foreign.ValueLayout.JAVA_INT;
import static java.lang.foreign.ValueLayout.JAVA_LONG;

import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.Linker;
import java.lang.foreign.SymbolLookup;
import java.lang.invoke.MethodHandle;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ForeignFunctionClass {

private static final Logger LOGGER = LoggerFactory.getLogger(ForeignFunctionClass.class);

public void execute() {
LOGGER.info("Running foreign function sleep...");

Linker linker = Linker.nativeLinker();
SymbolLookup stdlib = linker.defaultLookup();
MethodHandle sleep = linker.downcallHandle(stdlib.find("sleep")
.orElseThrow(), FunctionDescriptor.of(JAVA_INT, JAVA_LONG));

try {
sleep.invoke(100);
} catch (Throwable ex) {
System.out.println("Error in native sleep...");
throw new RuntimeException(ex);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.baeldung.virtualthread.nativemethod;

public class NativeDemo {

static {
System.loadLibrary("native-lib");
}

public native String nativeCall();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.baeldung.virtualthread.synchronize;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;

@BenchmarkMode({ Mode.AverageTime, Mode.Throughput })
@OutputTimeUnit(TimeUnit.SECONDS)
@Warmup(iterations = 1, time = 5, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 3, time = 5, timeUnit = TimeUnit.SECONDS)
@Fork(value = 2)
@State(Scope.Benchmark)
public class BenchmarkVirtualThread {

private final CartService cartService = new CartService();

@Param({ "100", "1000", "10000" })
private int CONCURRENCY;

@Benchmark
public void benchmark() throws InterruptedException, IOException {
List<Thread> threads = new ArrayList<>();
IntStream.range(0, CONCURRENCY).forEach(i -> threads.add(Thread.startVirtualThread(() -> cartService.update(UUID.randomUUID()
.toString(), 2))));

threads.forEach(th -> {
try {
th.join();
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.baeldung.virtualthread.synchronize;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CartService {

private static final Logger LOGGER = LoggerFactory.getLogger(CartService.class);

private final Map<String, Integer> products;
private final Map<String, Object> locks = new ConcurrentHashMap<>();

public CartService() {
this.products = new HashMap<>();
}

public void update(String productId, int quantity) {
Object lock = locks.computeIfAbsent(productId, k -> new Object());

synchronized (lock) {
simulateAPI();
products.merge(productId, quantity, Integer::sum);
}

LOGGER.info("Updated Cart for {} {}", productId, quantity);
}

public Map<String, Integer> getProducts() {
return Map.copyOf(products);
}

private void simulateAPI() {
try {
Thread.sleep(50);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.baeldung.virtualthread.synchronize.fixed;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CartService {

private static final Logger LOGGER = LoggerFactory.getLogger(CartService.class);

private final Map<String, Integer> products;
private final Map<String, ReentrantLock> locks = new ConcurrentHashMap<>();

public CartService() {
this.products = new HashMap<>();
}

public void update(String productId, int quantity) {
Lock lock = locks.computeIfAbsent(productId, k -> new ReentrantLock());

try {
if (lock.tryLock(500, TimeUnit.MILLISECONDS)) {
try {
simulateAPI();
products.merge(productId, quantity, Integer::sum);
} finally {
lock.unlock();
}
LOGGER.info("Updated Cart for {} {}", productId, quantity);
}
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}

private void simulateAPI() {
try {
Thread.sleep(50);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}

public Map<String, Integer> getProducts() {
return Map.copyOf(products);
}
}
Loading