Performance Optimization trong Java

1. Lý thuyết và Khái niệm Cơ bản

1.1 Các Khía Cạnh Hiệu Năng

  • Thời gian phản hồi (Response Time)
  • Thông lượng (Throughput)
  • Tải CPU (CPU Load)
  • Sử dụng bộ nhớ (Memory Usage)
  • Độ trễ mạng (Network Latency)
  • Tải I/O (I/O Load)

1.2 Các Yếu Tố Ảnh Hưởng

  • Cấu trúc code
  • Thuật toán và cấu trúc dữ liệu
  • Cấu hình JVM
  • Database queries
  • Network calls
  • File I/O operations

2. Best Practices và Design Patterns

2.1 Code Optimization

// Tối ưu String concatenation
public class StringOptimization {
    // Bad practice
    public String buildString(List<String> items) {
        String result = "";
        for (String item : items) {
            result += item + ", ";  // Creates new String object each time
        }
        return result;
    }

    // Good practice
    public String buildStringOptimized(List<String> items) {
        StringBuilder builder = new StringBuilder();
        for (String item : items) {
            builder.append(item).append(", ");
        }
        return builder.toString();
    }
}

// Tối ưu Collections
public class CollectionOptimization {
    // Initialize with proper size
    List<String> list = new ArrayList<>(initialCapacity);

    // Use proper collection type
    Set<String> uniqueItems = new HashSet<>();
    Map<String, Integer> frequencyMap = new HashMap<>();

    // Use stream for parallel processing
    public long countItems(List<String> items) {
        return items.parallelStream()
            .filter(item -> item.length() > 5)
            .count();
    }
}

2.2 Database Optimization

@Repository
public class OptimizedRepository {
    // Use proper indexing
    @Query("SELECT u FROM User u WHERE u.email = :email")
    Optional<User> findByEmail(@Param("email") String email);

    // Batch processing
    @Modifying
    @Query(value = "INSERT INTO users (name, email) VALUES :users", nativeQuery = true)
    void batchInsert(@Param("users") List<Object[]> users);

    // Pagination
    @Query("SELECT u FROM User u")
    Page<User> findAllPaginated(Pageable pageable);
}

3. Anti-patterns và Common Pitfalls

3.1 Memory Leaks

public class MemoryLeakExample {
    // Memory leak - forgetting to close resources
    public void badResourceHandling() {
        Connection conn = getConnection();
        // Use connection
        // Forgot to close
    }

    // Proper resource handling
    public void goodResourceHandling() {
        try (Connection conn = getConnection()) {
            // Use connection
            // Auto-closed by try-with-resources
        }
    }
}

3.2 Performance Anti-patterns

public class PerformanceAntiPatterns {
    // N+1 queries problem
    public void nPlusOneProblem() {
        List<Order> orders = orderRepository.findAll();
        for (Order order : orders) {
            // This causes N additional queries
            Customer customer = customerRepository.findById(order.getCustomerId());
            processOrder(order, customer);
        }
    }

    // Solution: Use JOIN FETCH
    @Query("SELECT o FROM Order o JOIN FETCH o.customer")
    List<Order> findAllWithCustomers();
}

4. Ví dụ Code Thực tế

4.1 Caching Implementation

@Service
public class CachedUserService {
    private final UserRepository userRepository;
    private final Cache<String, User> cache;

    public CachedUserService() {
        this.cache = Caffeine.newBuilder()
            .maximumSize(10_000)
            .expireAfterWrite(Duration.ofMinutes(5))
            .build();
    }

    public User getUser(String id) {
        return cache.get(id, key -> userRepository.findById(key)
            .orElseThrow(() -> new UserNotFoundException(id)));
    }

    public void invalidateCache(String id) {
        cache.invalidate(id);
    }
}

4.2 Async Processing

@Service
public class AsyncOrderProcessor {
    private final ExecutorService executor;

    public CompletableFuture<OrderResult> processOrder(Order order) {
        return CompletableFuture.supplyAsync(() -> {
            // Validate order
            validateOrder(order);

            // Process payment
            return processPayment(order);
        }, executor).thenApplyAsync(paymentResult -> {
            // Update inventory
            updateInventory(order);

            // Return result
            return new OrderResult(order, paymentResult);
        }, executor);
    }
}

5. Use Cases và Scenarios

5.1 High-Load System

@Configuration
public class HighLoadConfig {
    @Bean
    public ConnectionPool connectionPool() {
        return ConnectionPool.builder()
            .maxSize(100)
            .minIdle(10)
            .maxLifetime(Duration.ofMinutes(30))
            .build();
    }

    @Bean
    public CacheManager cacheManager() {
        return RedisCacheManager.builder(redisConnectionFactory())
            .cacheDefaults(RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(10)))
            .build();
    }
}

5.2 Batch Processing

@Service
public class BatchProcessor {
    private static final int BATCH_SIZE = 1000;

    public void processBatch(List<Item> items) {
        List<List<Item>> batches = Lists.partition(items, BATCH_SIZE);

        batches.parallelStream().forEach(batch -> {
            try {
                processBatchItems(batch);
            } catch (Exception e) {
                handleBatchError(batch, e);
            }
        });
    }
}

6. Performance Considerations

6.1 JVM Tuning

public class JvmConfig {
    // Example JVM arguments
    // -Xms2g -Xmx2g // Fixed heap size
    // -XX:+UseG1GC // Use G1 Garbage Collector
    // -XX:MaxGCPauseMillis=200 // Target GC pause time
    // -XX:+HeapDumpOnOutOfMemoryError // Create heap dump on OOM

    public void configureJvm() {
        // Get current memory usage
        Runtime runtime = Runtime.getRuntime();
        long maxMemory = runtime.maxMemory();
        long usedMemory = runtime.totalMemory() - runtime.freeMemory();

        // Log memory stats
        log.info("Max memory: {} MB", maxMemory / 1024 / 1024);
        log.info("Used memory: {} MB", usedMemory / 1024 / 1024);
    }
}

6.2 Database Tuning

@Configuration
public class DatabaseConfig {
    @Bean
    public HikariDataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setMaximumPoolSize(10);
        config.setMinimumIdle(5);
        config.setIdleTimeout(300000);
        config.setConnectionTimeout(20000);
        config.setMaxLifetime(1200000);

        return new HikariDataSource(config);
    }
}

7. Security Considerations

7.1 Secure Performance Optimization

public class SecureOptimization {
    private final RateLimiter rateLimiter;

    public Response processRequest(Request request) {
        // Rate limiting
        if (!rateLimiter.tryAcquire()) {
            throw new TooManyRequestsException();
        }

        // Input validation
        validateInput(request);

        // Process with timeout
        return processWithTimeout(request, Duration.ofSeconds(5));
    }
}

7.2 Resource Protection

public class ResourceProtection {
    private final Semaphore semaphore;

    public void processWithLimits() {
        try {
            if (semaphore.tryAcquire(1, TimeUnit.SECONDS)) {
                try {
                    // Process request
                    processRequest();
                } finally {
                    semaphore.release();
                }
            } else {
                throw new ResourceUnavailableException();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new ProcessingException(e);
        }
    }
}

8. Testing Strategies

8.1 Performance Testing

@SpringBootTest
public class PerformanceTest {
    @Test
    public void loadTest() {
        int threadCount = 100;
        int requestsPerThread = 1000;

        ExecutorService executor = Executors.newFixedThreadPool(threadCount);
        CountDownLatch latch = new CountDownLatch(threadCount);

        Stopwatch stopwatch = Stopwatch.createStarted();

        for (int i = 0; i < threadCount; i++) {
            executor.submit(() -> {
                try {
                    for (int j = 0; j < requestsPerThread; j++) {
                        service.processRequest();
                    }
                } finally {
                    latch.countDown();
                }
            });
        }

        latch.await(1, TimeUnit.MINUTES);
        stopwatch.stop();

        log.info("Total time: {} ms", stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }
}

8.2 Monitoring Tests

public class PerformanceMonitor {
    private final MeterRegistry registry;

    public void recordMetrics(String operation, long duration) {
        registry.timer("operation.duration",
            "operation", operation)
            .record(duration, TimeUnit.MILLISECONDS);

        registry.counter("operation.count",
            "operation", operation)
            .increment();
    }
}

9. Monitoring và Troubleshooting

9.1 Metrics Collection

@Configuration
public class MetricsConfig {
    @Bean
    public MeterRegistry meterRegistry() {
        CompositeMeterRegistry registry = new CompositeMeterRegistry();

        registry.config()
            .commonTags("application", "performance-demo")
            .meterFilter(MeterFilter.deny(id -> {
                String uri = id.getTag("uri");
                return uri != null && uri.startsWith("/admin");
            }));

        return registry;
    }
}

9.2 Performance Logging

@Aspect
@Component
public class PerformanceLoggingAspect {
    @Around("@annotation(LogPerformance)")
    public Object logPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
        Stopwatch stopwatch = Stopwatch.createStarted();

        try {
            return joinPoint.proceed();
        } finally {
            stopwatch.stop();
            log.info("Method {} took {} ms",
                joinPoint.getSignature().getName(),
                stopwatch.elapsed(TimeUnit.MILLISECONDS));
        }
    }
}

10. References và Further Reading

10.1 Performance Resources

  • Java Performance: The Definitive Guide
  • Optimizing Java
  • Java Performance Tuning
  • High Performance Java Persistence
  • Java Concurrency in Practice

10.2 Tools và Frameworks

  • JMeter for load testing
  • VisualVM for profiling
  • Micrometer for metrics
  • Prometheus for monitoring
  • Grafana for visualization