Spring Virtual Threads
Overview
Virtual Threads
Virtual threads (Project Loom) is part of Java 21. Any blocking operation doesn't cause the thread to block. Thread Pool are replaced with a virtual thread executor.
Github: https://github.com/gitorko/project58
To enable virtual threads in spring boot application
1spring.threads.virtual.enabled=true
Code
1package com.demo.project58.controller;
2
3import java.util.List;
4import java.util.UUID;
5
6import com.demo.project58.pojo.Customer;
7import com.demo.project58.service.CustomerService;
8import lombok.extern.slf4j.Slf4j;
9import org.springframework.beans.factory.annotation.Autowired;
10import org.springframework.data.domain.Page;
11import org.springframework.data.domain.PageRequest;
12import org.springframework.http.ResponseEntity;
13import org.springframework.transaction.annotation.Transactional;
14import org.springframework.web.bind.annotation.DeleteMapping;
15import org.springframework.web.bind.annotation.GetMapping;
16import org.springframework.web.bind.annotation.PathVariable;
17import org.springframework.web.bind.annotation.PostMapping;
18import org.springframework.web.bind.annotation.PutMapping;
19import org.springframework.web.bind.annotation.RequestBody;
20import org.springframework.web.bind.annotation.RequestMapping;
21import org.springframework.web.bind.annotation.RequestParam;
22import org.springframework.web.bind.annotation.RestController;
23import org.springframework.web.client.RestClient;
24
25@RestController
26@RequestMapping("/customer")
27@Slf4j
28public class CustomerController {
29
30 @Autowired
31 private CustomerService customerService;
32
33 @Autowired
34 private RestClient restClient;
35
36 @GetMapping("/greet/{name}")
37 public String greet(@PathVariable String name) {
38 return customerService.greet(name);
39 }
40
41 @PostMapping("/save")
42 @Transactional
43 public Customer saveCustomer(@RequestBody Customer customer) {
44 return customerService.save(customer);
45 }
46
47 @GetMapping("/all")
48 public List<Customer> findAll() {
49 return customerService.findAll();
50 }
51
52 @GetMapping("/{id}")
53 public Customer findById(@PathVariable UUID id) {
54 return customerService.findById(id);
55 }
56
57 @PutMapping(value = "/update")
58 public Customer update(@RequestBody Customer customer) {
59 return customerService.save(customer);
60 }
61
62 @DeleteMapping(value = "/{id}")
63 public void delete(@PathVariable UUID id) {
64 customerService.deleteById(id);
65 }
66
67 @GetMapping("/find")
68 public List<Customer> find(@RequestParam String name, @RequestParam Integer age) {
69 return customerService.findByNameAndAge(name, age);
70 }
71
72 @GetMapping("/page")
73 public Page<Customer> findPage(@RequestParam("page") int page, @RequestParam("size") int size) {
74 return customerService.findAll(PageRequest.of(page, size));
75 }
76
77 @GetMapping("/search")
78 public List<Customer> search(Customer customer) {
79 return customerService.search(customer);
80 }
81
82 @GetMapping("/block/{seconds}")
83 public String block(@PathVariable Integer seconds) {
84 ResponseEntity<Void> result = restClient.get()
85 .uri("/delay/" + seconds)
86 .retrieve()
87 .toBodilessEntity();
88
89 log.info("{} on {}", result.getStatusCode(), Thread.currentThread());
90 return Thread.currentThread().toString();
91 }
92}
1spring:
2 threads:
3 virtual:
4 enabled: true
5 task:
6 execution:
7 simple:
8 concurrency-limit: 10
9 scheduling:
10 simple:
11 concurrency-limit: 10
12 main:
13 banner-mode: "off"
14 datasource:
15 driver-class-name: org.postgresql.Driver
16 url: jdbc:postgresql://localhost:5432/test-db
17 username: test
18 password: test@123
19 jpa:
20 show-sql: false
21 liquibase:
22 enabled: true
23 change-log: db/changelog/db.changelog-main.yaml
24logging:
25 level:
26 org.springframework.data.jpa: DEBUG
Setup
1# Project 58
2
3Spring Virtual Threads & Unit Testing
4
5Checkstyle, SpotBugs, JaCoCo code coverage
6
7[https://gitorko.github.io/spring-virtual-threads/](https://gitorko.github.io/spring-virtual-threads/)
8
9### Version
10
11Check version
12
13```bash
14$java --version
15openjdk 21
16```
17
18Check apache benchmark
19```bash
20$ ab -V
21This is ApacheBench, Version 2.3 <$Revision: 1903618 $>
22```
23
24### Postgres DB
25
26```
27docker run -p 5432:5432 --name pg-container -e POSTGRES_PASSWORD=password -d postgres:9.6.10
28docker ps
29docker exec -it pg-container psql -U postgres -W postgres
30CREATE USER test WITH PASSWORD 'test@123';
31CREATE DATABASE "test-db" WITH OWNER "test" ENCODING UTF8 TEMPLATE template0;
32grant all PRIVILEGES ON DATABASE "test-db" to test;
33
34docker stop pg-container
35docker start pg-container
36```
37
38### Dev
39
40To build the code.
41
42```bash
43./gradlew clean build
44```
45
46```bash
47ab -n 10 -c 2 http://localhost:8080/customer/block/3
48```
References
comments powered by Disqus