Fundamentals 7 min read

Concurrency, Coroutines vs Threads, and Performance Optimization in Java/Kotlin

This article compares coroutines and threads for high‑concurrency and I/O‑intensive workloads, summarizes multithreading fundamentals, presents performance‑critical code examples, and discusses JVM memory, locking, middleware, and various optimization techniques for backend systems.

JD Tech Talk
JD Tech Talk
JD Tech Talk
Concurrency, Coroutines vs Threads, and Performance Optimization in Java/Kotlin

Coroutines vs Threads

Coroutines offer clear and efficient asynchronous code for high‑concurrency and I/O‑intensive tasks, while threads remain a mature choice for CPU‑bound workloads. The decision depends on the specific scenario, and Kotlin coroutines are increasingly supported by middleware and frameworks such as Akka and Spring WebFlux.

Multithreading Knowledge Summary

For basic concepts, refer to the author's previous blog post (https://blog.csdn.net/Zzhou1990/article/details/106008171). The article also includes visual diagrams of reactive programming.

Concurrency Issues with System.currentTimeMillis

The System.currentTimeMillis call invokes gettimeofday() , which requires a user‑to‑kernel mode switch and is affected by the Linux timer source (e.g., HPET), leading to contention under high concurrency. Middleware often uses a singleton thread to fetch time.

public final class TimeUtil {
    private static volatile long currentTimeMillis;
    static {
        currentTimeMillis = System.currentTimeMillis();
        Thread daemon = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    currentTimeMillis = System.currentTimeMillis();
                    try {
                        TimeUnit.MILLISECONDS.sleep(1);
                    } catch (Throwable e) {
                    }
                }
            }
        });
        daemon.setDaemon(true);
        daemon.setName("sentinel-time-tick-thread");
        daemon.start();
    }
    public static long currentTimeMillis() {
        return currentTimeMillis;
    }
}

JSON Conversion Performance Issue

List
vendorList = vendorInfoMapper.findVendorList();
log.info("日志输出:{}", JSONUtils.toJSONString(vendorList));

if (log.isInfoEnabled()){
    log.info("日志输出:{}", JSONUtils.toJSONString(vendorList));
}

Low‑Performance User Retrieval Example

class User {    private long id;    private String name;    private String email;}
public User getUserInfoLowPerformance(long userId) {
    String key = USER_INFO_KEY + ":" + userId;
    String jsonUser = (String) redisTemplate.opsForValue().get(key);
    if (jsonUser == null) {
        return null;
    }
    return new Gson().fromJson(jsonUser, User.class);
}
public User getUserInfo(long userId) {
    Map
userInfoMap = redisTemplate.opsForHash().entries(key);
    if (userInfoMap.isEmpty()) {
        return null;
    }
    User user = new User();
    user.setId((Long) userInfoMap.get("id"));
    user.setName((String) userInfoMap.get("name"));
    user.setEmail((String) userInfoMap.get("email"));
    // ...
}

Performance Optimization Techniques

Looping can amplify low‑performance code; using asynchronous or non‑critical operations can reduce latency. Optimize data access (O(1) lookups), leverage I/O, caching, and CPU‑efficient algorithms. Stream programming, Caffeine cache, and batch processing can cut blocking time (e.g., 50 ms → 15 ms).

Concurrency, Memory, and CPU

Understanding the JVM memory model, version‑specific behaviors, memory visibility, instruction reordering, and thread scheduling is essential. Proper GC parameter tuning and awareness of user‑kernel mode switches affect performance.

Locks

Choosing the right lock (mutex, spin, read‑write, optimistic, pessimistic, segment, CAS) significantly impacts concurrency.

Middleware Considerations

Performance is influenced by databases, caches, circuit breakers, service calls, configuration centers, tracing, logging, and messaging systems. Metrics such as TCP/HTTP connection latency, QPS/TPS, and response times vary with hardware (e.g., 4‑core/8 GB MySQL vs 8‑core/32 GB Redis).

Other Topics

Off‑heap memory reduces GC overhead; bytecode enhancement can improve performance; cache‑line size (64 KB), Disruptor, false sharing, and locality principles (spatial locality, branch optimization) are also discussed. References to flame‑graph analysis and CPU‑friendly coding are provided.

JavaJVMperformanceconcurrencyKotlinmultithreadingcoroutines
JD Tech Talk
Written by

JD Tech Talk

Official JD Tech public account delivering best practices and technology innovation.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.